Modelo

source("../../lib/som-utils.R")

Attaching package: 'dplyr'
The following objects are masked from 'package:stats':

    filter, lag
The following objects are masked from 'package:base':

    intersect, setdiff, setequal, union
source("../../lib/maps-utils.R")
Linking to GEOS 3.8.0, GDAL 3.0.4, PROJ 6.3.1

Carga del modelo desde disco

mpr.set_base_path_analysis()
model <- mpr.load_model("som-138.rds.xz")
summary(model)
SOM of size 5x5 with a hexagonal topology and a bubble neighbourhood function.
The number of data layers is 1.
Distance measure(s) used: sumofsquares.
Training data included: 156652 objects.
Mean distance to the closest unit in the map: 1.245.
plot(model, type="changes")

Carga del dataset de entrada

df <- mpr.load_data("datos_semana_2k.csv.xz")
df
summary(df)
 id_estacion           fecha             fecha_cnt          tmax       
 Length:156652      Length:156652      Min.   : 1.00   Min.   :-109.0  
 Class :character   Class :character   1st Qu.:13.00   1st Qu.: 147.0  
 Mode  :character   Mode  :character   Median :27.00   Median : 201.0  
                                       Mean   :26.53   Mean   : 202.1  
                                       3rd Qu.:40.00   3rd Qu.: 262.0  
                                       Max.   :53.00   Max.   : 442.0  
      tmin             precip           nevada    prof_nieve      
 Min.   :-189.00   Min.   :  0.00   Min.   :0   Min.   :   0.000  
 1st Qu.:  48.00   1st Qu.:  0.00   1st Qu.:0   1st Qu.:   0.000  
 Median :  98.00   Median :  3.00   Median :0   Median :   0.000  
 Mean   :  98.13   Mean   : 16.92   Mean   :0   Mean   :   0.604  
 3rd Qu.: 152.00   3rd Qu.: 20.00   3rd Qu.:0   3rd Qu.:   0.000  
 Max.   : 272.00   Max.   :690.00   Max.   :0   Max.   :1073.000  
    longitud        latitud           altitud      
 Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:39.01   1st Qu.: -4.850   1st Qu.:  44.0  
 Median :41.22   Median : -1.411   Median : 263.0  
 Mean   :40.05   Mean   : -2.426   Mean   : 478.5  
 3rd Qu.:42.19   3rd Qu.:  1.272   3rd Qu.: 687.0  
 Max.   :43.57   Max.   :  4.216   Max.   :2535.0  

Carga de los mapas

world <- ne_countries(scale = "medium", returnclass = "sf")
spain <- subset(world, admin == "Spain")

Mapa de densidad

plot(model, type="count", shape = "straight", palette.name = mpr.degrade.bleu)

NĂºmero de elementos en cada celda:

nb <- table(model$unit.classif)
print(nb)

    1     2     3     4     5     6     7     8     9    10    11    12    13 
 1121  4719 11151 10593  3495  8639  3714  9097  8333  4954  7185  6937  5162 
   14    15    16    17    18    19    20    21    22    23    24    25 
 4143   368 13036 10955  3851  3839  1944  7215  4010  6236  7909  8046 

ComprobaciĂ³n de nodos vacĂ­os:

dim_model <- 5*5;
len_nb = length(nb);
empty_nodes <- dim_model != len_nb;
if (empty_nodes) {
  print(paste("[Warning] Existen nodos vacĂ­os: ", len_nb, "/", dim_model))
}

Mapa de distancia entre vecinos

plot(model, type="dist.neighbours", shape = "straight")

Influencia de las variables

model_colnames = c("fecha_cnt", "tmax", "tmin", "precip", "longitud", "latitud", "altitud")
model_ncol = length(model_colnames)

Mapa de variables.

plot(model, shape = "straight")

Mapa de calor por variable

par(mfrow=c(3,4))
for (j in 1:model_ncol) {
  plot(model, type="property", property=getCodes(model,1)[,j],
    palette.name=mpr.coolBlueHotRed,
    main=model_colnames[j],
    cex=0.5, shape = "straight")
}

CorrelaciĂ³n para cada columna del vector de nodos

if (!empty_nodes) {
  cor <- apply(getCodes(model,1), 2, mpr.weighted.correlation, w=nb, som=model)
  print(cor)
}
       fecha_cnt       tmax       tmin     precip  longitud   latitud
[1,] -0.03557622 -0.8565794 -0.8776397 0.32580963 0.4636383 0.3661047
[2,]  0.83570953  0.3489841  0.3173693 0.07285726 0.2209775 0.1843679
        altitud
[1,]  0.4167247
[2,] -0.1534604

RepresentaciĂ³n de cada variable en un mapa de factores:

if (!empty_nodes) {
  par(mfrow=c(1,1))
  plot(cor[1,], cor[2,], xlim=c(-1,1), ylim=c(-1,1), type="n")
  lines(c(-1,1),c(0,0))
  lines(c(0,0),c(-1,1))
  text(cor[1,], cor[2,], labels=model_colnames, cex=0.75)
  symbols(0,0,circles=1,inches=F,add=T)
}

Importancia de cada variable - varianza ponderada por el tamaño de la celda:

if (!empty_nodes) {
  sigma2 <- sqrt(apply(getCodes(model,1),2,function(x,effectif)
     {m<-sum(effectif*(x-weighted.mean(x,effectif))^2)/(sum(effectif)-1)},
     effectif=nb))
  print(sort(sigma2,decreasing=T))
}
 longitud   altitud      tmax fecha_cnt      tmin   latitud    precip 
0.9474891 0.9288958 0.9180225 0.9099413 0.9061943 0.8942628 0.8747383 

Clustering

if (!empty_nodes) {
  hac <- mpr.hac(model, nb)
}

VisualizaciĂ³n de 3 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=3)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=3)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt          tmax            tmin           precip           nevada 
 Min.   : 1.00   Min.   : -3.0   Min.   :-51.0   Min.   :  0.00   Min.   :0  
 1st Qu.:13.00   1st Qu.:211.0   1st Qu.:149.0   1st Qu.:  0.00   1st Qu.:0  
 Median :26.00   Median :234.0   Median :172.0   Median :  0.00   Median :0  
 Mean   :26.29   Mean   :229.6   Mean   :165.2   Mean   :  5.41   Mean   :0  
 3rd Qu.:39.00   3rd Qu.:262.0   3rd Qu.:201.0   3rd Qu.:  2.00   3rd Qu.:0  
 Max.   :53.00   Max.   :384.0   Max.   :263.0   Max.   :193.00   Max.   :0  
   prof_nieve    longitud        latitud          altitud      
 Min.   :0    Min.   :27.82   Min.   :-17.89   Min.   :  14.0  
 1st Qu.:0    1st Qu.:28.05   1st Qu.:-16.56   1st Qu.:  25.0  
 Median :0    Median :28.44   Median :-16.33   Median :  33.0  
 Mean   :0    Mean   :28.35   Mean   :-16.03   Mean   : 369.7  
 3rd Qu.:0    3rd Qu.:28.48   3rd Qu.:-15.39   3rd Qu.:  64.0  
 Max.   :0    Max.   :28.95   Max.   :-13.60   Max.   :2371.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt          tmax             tmin             precip      
 Min.   : 1.00   Min.   :-109.0   Min.   :-189.00   Min.   :  0.00  
 1st Qu.:13.00   1st Qu.: 144.0   1st Qu.:  45.00   1st Qu.:  0.00  
 Median :27.00   Median : 196.0   Median :  93.00   Median :  4.00  
 Mean   :26.53   Mean   : 200.4   Mean   :  93.73   Mean   : 16.99  
 3rd Qu.:40.00   3rd Qu.: 262.0   3rd Qu.: 145.00   3rd Qu.: 22.00  
 Max.   :53.00   Max.   : 442.0   Max.   : 272.00   Max.   :239.00  
     nevada    prof_nieve           longitud        latitud       
 Min.   :0   Min.   :   0.0000   Min.   :27.82   Min.   :-17.889  
 1st Qu.:0   1st Qu.:   0.0000   1st Qu.:39.88   1st Qu.: -4.049  
 Median :0   Median :   0.0000   Median :41.38   Median : -1.033  
 Mean   :0   Mean   :   0.6288   Mean   :40.83   Mean   : -1.520  
 3rd Qu.:0   3rd Qu.:   0.0000   3rd Qu.:42.24   3rd Qu.:  1.363  
 Max.   :0   Max.   :1073.0000   Max.   :43.57   Max.   :  4.216  
    altitud    
 Min.   :   1  
 1st Qu.:  58  
 Median : 316  
 Mean   : 485  
 3rd Qu.: 704  
 Max.   :2535  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt          tmax            tmin            precip          nevada 
 Min.   : 1.00   Min.   :-58.0   Min.   :-103.0   Min.   :208.0   Min.   :0  
 1st Qu.: 9.75   1st Qu.: 90.0   1st Qu.:  35.5   1st Qu.:245.0   1st Qu.:0  
 Median :40.00   Median :133.0   Median :  75.0   Median :275.5   Median :0  
 Mean   :29.56   Mean   :130.1   Mean   :  69.0   Mean   :296.5   Mean   :0  
 3rd Qu.:46.00   3rd Qu.:179.2   3rd Qu.: 116.2   3rd Qu.:324.2   3rd Qu.:0  
 Max.   :53.00   Max.   :294.0   Max.   : 217.0   Max.   :690.0   Max.   :0  
   prof_nieve         longitud        latitud            altitud      
 Min.   :  0.000   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:  0.000   1st Qu.:40.78   1st Qu.: -5.6000   1st Qu.:  68.6  
 Median :  0.000   Median :42.12   Median :  0.0714   Median : 263.0  
 Mean   :  6.739   Mean   :40.83   Mean   : -2.4923   Mean   : 746.8  
 3rd Qu.:  0.000   3rd Qu.:42.53   3rd Qu.:  1.0989   3rd Qu.:1405.0  
 Max.   :685.000   Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

VisualizaciĂ³n de 4 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=4)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=4)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt          tmax            tmin           precip           nevada 
 Min.   : 1.00   Min.   : -3.0   Min.   :-51.0   Min.   :  0.00   Min.   :0  
 1st Qu.:13.00   1st Qu.:211.0   1st Qu.:149.0   1st Qu.:  0.00   1st Qu.:0  
 Median :26.00   Median :234.0   Median :172.0   Median :  0.00   Median :0  
 Mean   :26.29   Mean   :229.6   Mean   :165.2   Mean   :  5.41   Mean   :0  
 3rd Qu.:39.00   3rd Qu.:262.0   3rd Qu.:201.0   3rd Qu.:  2.00   3rd Qu.:0  
 Max.   :53.00   Max.   :384.0   Max.   :263.0   Max.   :193.00   Max.   :0  
   prof_nieve    longitud        latitud          altitud      
 Min.   :0    Min.   :27.82   Min.   :-17.89   Min.   :  14.0  
 1st Qu.:0    1st Qu.:28.05   1st Qu.:-16.56   1st Qu.:  25.0  
 Median :0    Median :28.44   Median :-16.33   Median :  33.0  
 Mean   :0    Mean   :28.35   Mean   :-16.03   Mean   : 369.7  
 3rd Qu.:0    3rd Qu.:28.48   3rd Qu.:-15.39   3rd Qu.:  64.0  
 Max.   :0    Max.   :28.95   Max.   :-13.60   Max.   :2371.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt          tmax            tmin             precip           nevada 
 Min.   : 1.00   Min.   :-31.0   Min.   :-189.00   Min.   :  0.00   Min.   :0  
 1st Qu.:14.00   1st Qu.:152.0   1st Qu.:  52.00   1st Qu.:  0.00   1st Qu.:0  
 Median :27.00   Median :203.0   Median :  98.00   Median :  3.00   Median :0  
 Mean   :26.52   Mean   :208.2   Mean   :  99.16   Mean   : 16.08   Mean   :0  
 3rd Qu.:39.00   3rd Qu.:267.0   3rd Qu.: 148.00   3rd Qu.: 20.00   3rd Qu.:0  
 Max.   :53.00   Max.   :442.0   Max.   : 272.00   Max.   :239.00   Max.   :0  
   prof_nieve          longitud        latitud           altitud    
 Min.   :  0.0000   Min.   :27.82   Min.   :-17.889   Min.   :   1  
 1st Qu.:  0.0000   1st Qu.:39.56   1st Qu.: -4.127   1st Qu.:  52  
 Median :  0.0000   Median :41.29   Median : -1.293   Median : 261  
 Mean   :  0.1418   Mean   :40.74   Mean   : -1.668   Mean   : 379  
 3rd Qu.:  0.0000   3rd Qu.:42.12   3rd Qu.:  1.296   3rd Qu.: 639  
 Max.   :948.0000   Max.   :43.57   Max.   :  4.216   Max.   :2535  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt          tmax              tmin              precip     
 Min.   : 1.00   Min.   :-109.00   Min.   :-175.000   Min.   :  0.0  
 1st Qu.:13.00   1st Qu.:  25.00   1st Qu.: -37.000   1st Qu.:  5.0  
 Median :26.00   Median :  68.00   Median :   3.000   Median : 21.0  
 Mean   :26.74   Mean   :  72.87   Mean   :   4.996   Mean   : 31.8  
 3rd Qu.:41.00   3rd Qu.: 124.00   3rd Qu.:  52.000   3rd Qu.: 48.0  
 Max.   :53.00   Max.   : 230.00   Max.   : 148.000   Max.   :200.0  
     nevada    prof_nieve          longitud        latitud       
 Min.   :0   Min.   :   0.000   Min.   :40.78   Min.   :-4.0103  
 1st Qu.:0   1st Qu.:   0.000   1st Qu.:42.29   1st Qu.: 0.7789  
 Median :0   Median :   0.000   Median :42.47   Median : 1.2717  
 Mean   :0   Mean   :   8.588   Mean   :42.32   Mean   : 0.8968  
 3rd Qu.:0   3rd Qu.:   0.000   3rd Qu.:42.64   3rd Qu.: 1.7150  
 Max.   :0   Max.   :1073.000   Max.   :42.77   Max.   : 2.4378  
    altitud    
 Min.   :1055  
 1st Qu.:2143  
 Median :2247  
 Mean   :2218  
 3rd Qu.:2400  
 Max.   :2535  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt          tmax            tmin            precip          nevada 
 Min.   : 1.00   Min.   :-58.0   Min.   :-103.0   Min.   :208.0   Min.   :0  
 1st Qu.: 9.75   1st Qu.: 90.0   1st Qu.:  35.5   1st Qu.:245.0   1st Qu.:0  
 Median :40.00   Median :133.0   Median :  75.0   Median :275.5   Median :0  
 Mean   :29.56   Mean   :130.1   Mean   :  69.0   Mean   :296.5   Mean   :0  
 3rd Qu.:46.00   3rd Qu.:179.2   3rd Qu.: 116.2   3rd Qu.:324.2   3rd Qu.:0  
 Max.   :53.00   Max.   :294.0   Max.   : 217.0   Max.   :690.0   Max.   :0  
   prof_nieve         longitud        latitud            altitud      
 Min.   :  0.000   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:  0.000   1st Qu.:40.78   1st Qu.: -5.6000   1st Qu.:  68.6  
 Median :  0.000   Median :42.12   Median :  0.0714   Median : 263.0  
 Mean   :  6.739   Mean   :40.83   Mean   : -2.4923   Mean   : 746.8  
 3rd Qu.:  0.000   3rd Qu.:42.53   3rd Qu.:  1.0989   3rd Qu.:1405.0  
 Max.   :685.000   Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

VisualizaciĂ³n de 5 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=5)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=5)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)
  df.cluster05 <- subset(df, cluster==5)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster05 <- select(df.cluster05, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt          tmax            tmin           precip           nevada 
 Min.   : 1.00   Min.   : -3.0   Min.   :-51.0   Min.   :  0.00   Min.   :0  
 1st Qu.:13.00   1st Qu.:211.0   1st Qu.:149.0   1st Qu.:  0.00   1st Qu.:0  
 Median :26.00   Median :234.0   Median :172.0   Median :  0.00   Median :0  
 Mean   :26.29   Mean   :229.6   Mean   :165.2   Mean   :  5.41   Mean   :0  
 3rd Qu.:39.00   3rd Qu.:262.0   3rd Qu.:201.0   3rd Qu.:  2.00   3rd Qu.:0  
 Max.   :53.00   Max.   :384.0   Max.   :263.0   Max.   :193.00   Max.   :0  
   prof_nieve    longitud        latitud          altitud      
 Min.   :0    Min.   :27.82   Min.   :-17.89   Min.   :  14.0  
 1st Qu.:0    1st Qu.:28.05   1st Qu.:-16.56   1st Qu.:  25.0  
 Median :0    Median :28.44   Median :-16.33   Median :  33.0  
 Mean   :0    Mean   :28.35   Mean   :-16.03   Mean   : 369.7  
 3rd Qu.:0    3rd Qu.:28.48   3rd Qu.:-15.39   3rd Qu.:  64.0  
 Max.   :0    Max.   :28.95   Max.   :-13.60   Max.   :2371.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt         tmax            tmin             precip           nevada 
 Min.   : 1.0   Min.   :-31.0   Min.   :-189.00   Min.   : 0.000   Min.   :0  
 1st Qu.:13.0   1st Qu.:155.0   1st Qu.:  50.00   1st Qu.: 0.000   1st Qu.:0  
 Median :26.0   Median :208.0   Median : 100.00   Median : 2.000   Median :0  
 Mean   :26.1   Mean   :211.5   Mean   :  99.69   Mean   : 8.511   Mean   :0  
 3rd Qu.:38.0   3rd Qu.:272.0   3rd Qu.: 151.00   3rd Qu.:13.000   3rd Qu.:0  
 Max.   :53.0   Max.   :442.0   Max.   : 272.00   Max.   :75.000   Max.   :0  
   prof_nieve          longitud        latitud          altitud      
 Min.   :  0.0000   Min.   :35.28   Min.   :-8.624   Min.   :   1.0  
 1st Qu.:  0.0000   1st Qu.:39.49   1st Qu.:-4.127   1st Qu.:  52.0  
 Median :  0.0000   Median :41.19   Median :-1.229   Median : 261.0  
 Mean   :  0.0971   Mean   :40.66   Mean   :-1.655   Mean   : 381.2  
 3rd Qu.:  0.0000   3rd Qu.:42.07   3rd Qu.: 1.201   3rd Qu.: 656.0  
 Max.   :484.0000   Max.   :43.57   Max.   : 4.216   Max.   :2143.0  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt          tmax              tmin              precip     
 Min.   : 1.00   Min.   :-109.00   Min.   :-175.000   Min.   :  0.0  
 1st Qu.:13.00   1st Qu.:  25.00   1st Qu.: -37.000   1st Qu.:  5.0  
 Median :26.00   Median :  68.00   Median :   3.000   Median : 21.0  
 Mean   :26.74   Mean   :  72.87   Mean   :   4.996   Mean   : 31.8  
 3rd Qu.:41.00   3rd Qu.: 124.00   3rd Qu.:  52.000   3rd Qu.: 48.0  
 Max.   :53.00   Max.   : 230.00   Max.   : 148.000   Max.   :200.0  
     nevada    prof_nieve          longitud        latitud       
 Min.   :0   Min.   :   0.000   Min.   :40.78   Min.   :-4.0103  
 1st Qu.:0   1st Qu.:   0.000   1st Qu.:42.29   1st Qu.: 0.7789  
 Median :0   Median :   0.000   Median :42.47   Median : 1.2717  
 Mean   :0   Mean   :   8.588   Mean   :42.32   Mean   : 0.8968  
 3rd Qu.:0   3rd Qu.:   0.000   3rd Qu.:42.64   3rd Qu.: 1.7150  
 Max.   :0   Max.   :1073.000   Max.   :42.77   Max.   : 2.4378  
    altitud    
 Min.   :1055  
 1st Qu.:2143  
 Median :2247  
 Mean   :2218  
 3rd Qu.:2400  
 Max.   :2535  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt          tmax            tmin            precip           nevada 
 Min.   : 1.00   Min.   :-15.0   Min.   :-84.00   Min.   : 18.00   Min.   :0  
 1st Qu.:16.00   1st Qu.:137.0   1st Qu.: 61.00   1st Qu.: 56.00   1st Qu.:0  
 Median :35.00   Median :172.0   Median : 92.00   Median : 74.00   Median :0  
 Mean   :30.28   Mean   :179.2   Mean   : 94.44   Mean   : 83.46   Mean   :0  
 3rd Qu.:44.00   3rd Qu.:219.0   3rd Qu.:127.00   3rd Qu.:101.00   3rd Qu.:0  
 Max.   :53.00   Max.   :407.0   Max.   :247.00   Max.   :239.00   Max.   :0  
   prof_nieve          longitud        latitud           altitud      
 Min.   :  0.0000   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:  0.0000   1st Qu.:40.95   1st Qu.: -4.846   1st Qu.:  58.0  
 Median :  0.0000   Median :41.88   Median : -1.636   Median : 252.0  
 Mean   :  0.5395   Mean   :41.47   Mean   : -1.779   Mean   : 359.2  
 3rd Qu.:  0.0000   3rd Qu.:42.70   3rd Qu.:  1.633   3rd Qu.: 567.0  
 Max.   :948.0000   Max.   :43.57   Max.   :  4.216   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster05)
   fecha_cnt          tmax            tmin            precip          nevada 
 Min.   : 1.00   Min.   :-58.0   Min.   :-103.0   Min.   :208.0   Min.   :0  
 1st Qu.: 9.75   1st Qu.: 90.0   1st Qu.:  35.5   1st Qu.:245.0   1st Qu.:0  
 Median :40.00   Median :133.0   Median :  75.0   Median :275.5   Median :0  
 Mean   :29.56   Mean   :130.1   Mean   :  69.0   Mean   :296.5   Mean   :0  
 3rd Qu.:46.00   3rd Qu.:179.2   3rd Qu.: 116.2   3rd Qu.:324.2   3rd Qu.:0  
 Max.   :53.00   Max.   :294.0   Max.   : 217.0   Max.   :690.0   Max.   :0  
   prof_nieve         longitud        latitud            altitud      
 Min.   :  0.000   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:  0.000   1st Qu.:40.78   1st Qu.: -5.6000   1st Qu.:  68.6  
 Median :  0.000   Median :42.12   Median :  0.0714   Median : 263.0  
 Mean   :  6.739   Mean   :40.83   Mean   : -2.4923   Mean   : 746.8  
 3rd Qu.:  0.000   3rd Qu.:42.53   3rd Qu.:  1.0989   3rd Qu.:1405.0  
 Max.   :685.000   Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1], dim(df.cluster05)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04", "cluster05"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.hist(df.cluster05)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster05)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
  df.cluster05.grouped <- mpr.group_by_geo(df.cluster05)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster05.grouped)

VisualizaciĂ³n de 6 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=6)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=6)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)
  df.cluster05 <- subset(df, cluster==5)
  df.cluster06 <- subset(df, cluster==6)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster05 <- select(df.cluster05, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster06 <- select(df.cluster06, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt          tmax            tmin           precip           nevada 
 Min.   : 1.00   Min.   : -3.0   Min.   :-51.0   Min.   :  0.00   Min.   :0  
 1st Qu.:13.00   1st Qu.:211.0   1st Qu.:149.0   1st Qu.:  0.00   1st Qu.:0  
 Median :26.00   Median :234.0   Median :172.0   Median :  0.00   Median :0  
 Mean   :26.29   Mean   :229.6   Mean   :165.2   Mean   :  5.41   Mean   :0  
 3rd Qu.:39.00   3rd Qu.:262.0   3rd Qu.:201.0   3rd Qu.:  2.00   3rd Qu.:0  
 Max.   :53.00   Max.   :384.0   Max.   :263.0   Max.   :193.00   Max.   :0  
   prof_nieve    longitud        latitud          altitud      
 Min.   :0    Min.   :27.82   Min.   :-17.89   Min.   :  14.0  
 1st Qu.:0    1st Qu.:28.05   1st Qu.:-16.56   1st Qu.:  25.0  
 Median :0    Median :28.44   Median :-16.33   Median :  33.0  
 Mean   :0    Mean   :28.35   Mean   :-16.03   Mean   : 369.7  
 3rd Qu.:0    3rd Qu.:28.48   3rd Qu.:-15.39   3rd Qu.:  64.0  
 Max.   :0    Max.   :28.95   Max.   :-13.60   Max.   :2371.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt          tmax            tmin             precip          nevada 
 Min.   : 1.00   Min.   :-22.0   Min.   :-189.00   Min.   : 0.00   Min.   :0  
 1st Qu.: 6.00   1st Qu.:136.0   1st Qu.:  29.00   1st Qu.: 0.00   1st Qu.:0  
 Median :11.00   Median :171.0   Median :  65.00   Median : 4.00   Median :0  
 Mean   :11.45   Mean   :171.1   Mean   :  63.57   Mean   :10.94   Mean   :0  
 3rd Qu.:17.00   3rd Qu.:208.0   3rd Qu.:  98.00   3rd Qu.:17.00   3rd Qu.:0  
 Max.   :31.00   Max.   :327.0   Max.   : 202.00   Max.   :74.00   Max.   :0  
   prof_nieve          longitud        latitud          altitud      
 Min.   :  0.0000   Min.   :35.28   Min.   :-8.624   Min.   :   1.0  
 1st Qu.:  0.0000   1st Qu.:39.49   1st Qu.:-4.127   1st Qu.:  47.0  
 Median :  0.0000   Median :41.20   Median :-1.229   Median : 258.0  
 Mean   :  0.1938   Mean   :40.65   Mean   :-1.591   Mean   : 375.3  
 3rd Qu.:  0.0000   3rd Qu.:42.07   3rd Qu.: 1.331   3rd Qu.: 656.0  
 Max.   :484.0000   Max.   :43.57   Max.   : 4.216   Max.   :1894.0  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt          tmax              tmin              precip     
 Min.   : 1.00   Min.   :-109.00   Min.   :-175.000   Min.   :  0.0  
 1st Qu.:13.00   1st Qu.:  25.00   1st Qu.: -37.000   1st Qu.:  5.0  
 Median :26.00   Median :  68.00   Median :   3.000   Median : 21.0  
 Mean   :26.74   Mean   :  72.87   Mean   :   4.996   Mean   : 31.8  
 3rd Qu.:41.00   3rd Qu.: 124.00   3rd Qu.:  52.000   3rd Qu.: 48.0  
 Max.   :53.00   Max.   : 230.00   Max.   : 148.000   Max.   :200.0  
     nevada    prof_nieve          longitud        latitud       
 Min.   :0   Min.   :   0.000   Min.   :40.78   Min.   :-4.0103  
 1st Qu.:0   1st Qu.:   0.000   1st Qu.:42.29   1st Qu.: 0.7789  
 Median :0   Median :   0.000   Median :42.47   Median : 1.2717  
 Mean   :0   Mean   :   8.588   Mean   :42.32   Mean   : 0.8968  
 3rd Qu.:0   3rd Qu.:   0.000   3rd Qu.:42.64   3rd Qu.: 1.7150  
 Max.   :0   Max.   :1073.000   Max.   :42.77   Max.   : 2.4378  
    altitud    
 Min.   :1055  
 1st Qu.:2143  
 Median :2247  
 Mean   :2218  
 3rd Qu.:2400  
 Max.   :2535  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt          tmax            tmin            precip           nevada 
 Min.   :13.00   Min.   :-31.0   Min.   :-155.0   Min.   : 0.000   Min.   :0  
 1st Qu.:29.00   1st Qu.:187.0   1st Qu.:  84.0   1st Qu.: 0.000   1st Qu.:0  
 Median :37.00   Median :255.0   Median : 136.0   Median : 1.000   Median :0  
 Mean   :36.93   Mean   :241.3   Mean   : 126.4   Mean   : 6.716   Mean   :0  
 3rd Qu.:45.00   3rd Qu.:299.0   3rd Qu.: 176.0   3rd Qu.: 9.000   3rd Qu.:0  
 Max.   :53.00   Max.   :442.0   Max.   : 272.0   Max.   :75.000   Max.   :0  
   prof_nieve           longitud        latitud          altitud      
 Min.   :  0.00000   Min.   :35.28   Min.   :-8.624   Min.   :   1.0  
 1st Qu.:  0.00000   1st Qu.:39.49   1st Qu.:-4.127   1st Qu.:  52.0  
 Median :  0.00000   Median :41.17   Median :-1.293   Median : 261.0  
 Mean   :  0.02559   Mean   :40.66   Mean   :-1.703   Mean   : 385.6  
 3rd Qu.:  0.00000   3rd Qu.:42.07   3rd Qu.: 1.179   3rd Qu.: 667.0  
 Max.   :290.00000   Max.   :43.57   Max.   : 4.216   Max.   :2143.0  
if (!empty_nodes) summary(df.cluster05)
   fecha_cnt          tmax            tmin            precip           nevada 
 Min.   : 1.00   Min.   :-15.0   Min.   :-84.00   Min.   : 18.00   Min.   :0  
 1st Qu.:16.00   1st Qu.:137.0   1st Qu.: 61.00   1st Qu.: 56.00   1st Qu.:0  
 Median :35.00   Median :172.0   Median : 92.00   Median : 74.00   Median :0  
 Mean   :30.28   Mean   :179.2   Mean   : 94.44   Mean   : 83.46   Mean   :0  
 3rd Qu.:44.00   3rd Qu.:219.0   3rd Qu.:127.00   3rd Qu.:101.00   3rd Qu.:0  
 Max.   :53.00   Max.   :407.0   Max.   :247.00   Max.   :239.00   Max.   :0  
   prof_nieve          longitud        latitud           altitud      
 Min.   :  0.0000   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:  0.0000   1st Qu.:40.95   1st Qu.: -4.846   1st Qu.:  58.0  
 Median :  0.0000   Median :41.88   Median : -1.636   Median : 252.0  
 Mean   :  0.5395   Mean   :41.47   Mean   : -1.779   Mean   : 359.2  
 3rd Qu.:  0.0000   3rd Qu.:42.70   3rd Qu.:  1.633   3rd Qu.: 567.0  
 Max.   :948.0000   Max.   :43.57   Max.   :  4.216   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster06)
   fecha_cnt          tmax            tmin            precip          nevada 
 Min.   : 1.00   Min.   :-58.0   Min.   :-103.0   Min.   :208.0   Min.   :0  
 1st Qu.: 9.75   1st Qu.: 90.0   1st Qu.:  35.5   1st Qu.:245.0   1st Qu.:0  
 Median :40.00   Median :133.0   Median :  75.0   Median :275.5   Median :0  
 Mean   :29.56   Mean   :130.1   Mean   :  69.0   Mean   :296.5   Mean   :0  
 3rd Qu.:46.00   3rd Qu.:179.2   3rd Qu.: 116.2   3rd Qu.:324.2   3rd Qu.:0  
 Max.   :53.00   Max.   :294.0   Max.   : 217.0   Max.   :690.0   Max.   :0  
   prof_nieve         longitud        latitud            altitud      
 Min.   :  0.000   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:  0.000   1st Qu.:40.78   1st Qu.: -5.6000   1st Qu.:  68.6  
 Median :  0.000   Median :42.12   Median :  0.0714   Median : 263.0  
 Mean   :  6.739   Mean   :40.83   Mean   : -2.4923   Mean   : 746.8  
 3rd Qu.:  0.000   3rd Qu.:42.53   3rd Qu.:  1.0989   3rd Qu.:1405.0  
 Max.   :685.000   Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1], dim(df.cluster05)[1], dim(df.cluster06)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04", "cluster05", "cluster06"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.hist(df.cluster05)

if (!empty_nodes) mpr.hist(df.cluster06)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster05)

if (!empty_nodes) mpr.boxplot(df.cluster06)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
  df.cluster05.grouped <- mpr.group_by_geo(df.cluster05)
  df.cluster06.grouped <- mpr.group_by_geo(df.cluster06)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster05.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster06.grouped)

VisualizaciĂ³n de 8 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=8)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=8)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)
  df.cluster05 <- subset(df, cluster==5)
  df.cluster06 <- subset(df, cluster==6)
  df.cluster07 <- subset(df, cluster==7)
  df.cluster08 <- subset(df, cluster==8)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster05 <- select(df.cluster05, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster06 <- select(df.cluster06, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster07 <- select(df.cluster07, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster08 <- select(df.cluster08, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt          tmax            tmin            precip           nevada 
 Min.   : 1.00   Min.   : -3.0   Min.   :-51.00   Min.   :  0.00   Min.   :0  
 1st Qu.:13.00   1st Qu.:101.0   1st Qu.: 28.00   1st Qu.:  0.00   1st Qu.:0  
 Median :26.00   Median :140.0   Median : 61.00   Median :  0.00   Median :0  
 Mean   :26.37   Mean   :144.6   Mean   : 68.24   Mean   :  7.54   Mean   :0  
 3rd Qu.:39.00   3rd Qu.:191.0   3rd Qu.:109.00   3rd Qu.:  3.00   3rd Qu.:0  
 Max.   :53.00   Max.   :263.0   Max.   :184.00   Max.   :193.00   Max.   :0  
   prof_nieve    longitud        latitud         altitud    
 Min.   :0    Min.   :28.31   Min.   :-16.5   Min.   :2371  
 1st Qu.:0    1st Qu.:28.31   1st Qu.:-16.5   1st Qu.:2371  
 Median :0    Median :28.31   Median :-16.5   Median :2371  
 Mean   :0    Mean   :28.31   Mean   :-16.5   Mean   :2371  
 3rd Qu.:0    3rd Qu.:28.31   3rd Qu.:-16.5   3rd Qu.:2371  
 Max.   :0    Max.   :28.31   Max.   :-16.5   Max.   :2371  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt          tmax            tmin             precip          nevada 
 Min.   : 1.00   Min.   :-22.0   Min.   :-189.00   Min.   : 0.00   Min.   :0  
 1st Qu.: 6.00   1st Qu.:136.0   1st Qu.:  29.00   1st Qu.: 0.00   1st Qu.:0  
 Median :11.00   Median :171.0   Median :  65.00   Median : 4.00   Median :0  
 Mean   :11.45   Mean   :171.1   Mean   :  63.57   Mean   :10.94   Mean   :0  
 3rd Qu.:17.00   3rd Qu.:208.0   3rd Qu.:  98.00   3rd Qu.:17.00   3rd Qu.:0  
 Max.   :31.00   Max.   :327.0   Max.   : 202.00   Max.   :74.00   Max.   :0  
   prof_nieve          longitud        latitud          altitud      
 Min.   :  0.0000   Min.   :35.28   Min.   :-8.624   Min.   :   1.0  
 1st Qu.:  0.0000   1st Qu.:39.49   1st Qu.:-4.127   1st Qu.:  47.0  
 Median :  0.0000   Median :41.20   Median :-1.229   Median : 258.0  
 Mean   :  0.1938   Mean   :40.65   Mean   :-1.591   Mean   : 375.3  
 3rd Qu.:  0.0000   3rd Qu.:42.07   3rd Qu.: 1.331   3rd Qu.: 656.0  
 Max.   :484.0000   Max.   :43.57   Max.   : 4.216   Max.   :1894.0  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt          tmax              tmin              precip     
 Min.   : 1.00   Min.   :-109.00   Min.   :-175.000   Min.   :  0.0  
 1st Qu.:13.00   1st Qu.:  25.00   1st Qu.: -37.000   1st Qu.:  5.0  
 Median :26.00   Median :  68.00   Median :   3.000   Median : 21.0  
 Mean   :26.74   Mean   :  72.87   Mean   :   4.996   Mean   : 31.8  
 3rd Qu.:41.00   3rd Qu.: 124.00   3rd Qu.:  52.000   3rd Qu.: 48.0  
 Max.   :53.00   Max.   : 230.00   Max.   : 148.000   Max.   :200.0  
     nevada    prof_nieve          longitud        latitud       
 Min.   :0   Min.   :   0.000   Min.   :40.78   Min.   :-4.0103  
 1st Qu.:0   1st Qu.:   0.000   1st Qu.:42.29   1st Qu.: 0.7789  
 Median :0   Median :   0.000   Median :42.47   Median : 1.2717  
 Mean   :0   Mean   :   8.588   Mean   :42.32   Mean   : 0.8968  
 3rd Qu.:0   3rd Qu.:   0.000   3rd Qu.:42.64   3rd Qu.: 1.7150  
 Max.   :0   Max.   :1073.000   Max.   :42.77   Max.   : 2.4378  
    altitud    
 Min.   :1055  
 1st Qu.:2143  
 Median :2247  
 Mean   :2218  
 3rd Qu.:2400  
 Max.   :2535  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt          tmax            tmin           precip            nevada 
 Min.   : 1.00   Min.   :126.0   Min.   : 67.0   Min.   :  0.000   Min.   :0  
 1st Qu.:13.00   1st Qu.:218.0   1st Qu.:157.0   1st Qu.:  0.000   1st Qu.:0  
 Median :26.00   Median :239.0   Median :177.0   Median :  0.000   Median :0  
 Mean   :26.28   Mean   :240.7   Mean   :177.8   Mean   :  5.133   Mean   :0  
 3rd Qu.:39.00   3rd Qu.:265.0   3rd Qu.:205.0   3rd Qu.:  2.000   3rd Qu.:0  
 Max.   :53.00   Max.   :384.0   Max.   :263.0   Max.   :160.000   Max.   :0  
   prof_nieve    longitud        latitud          altitud   
 Min.   :0    Min.   :27.82   Min.   :-17.89   Min.   : 14  
 1st Qu.:0    1st Qu.:28.05   1st Qu.:-17.75   1st Qu.: 25  
 Median :0    Median :28.46   Median :-16.33   Median : 33  
 Mean   :0    Mean   :28.36   Mean   :-15.97   Mean   :110  
 3rd Qu.:0    3rd Qu.:28.63   3rd Qu.:-13.86   3rd Qu.: 64  
 Max.   :0    Max.   :28.95   Max.   :-13.60   Max.   :632  
if (!empty_nodes) summary(df.cluster05)
   fecha_cnt          tmax            tmin           precip          nevada 
 Min.   :13.00   Min.   :129.0   Min.   : -9.0   Min.   : 0.00   Min.   :0  
 1st Qu.:27.00   1st Qu.:245.0   1st Qu.:127.0   1st Qu.: 0.00   1st Qu.:0  
 Median :32.00   Median :281.0   Median :158.0   Median : 0.00   Median :0  
 Mean   :32.66   Mean   :277.9   Mean   :156.3   Mean   : 5.89   Mean   :0  
 3rd Qu.:38.00   3rd Qu.:311.0   3rd Qu.:187.0   3rd Qu.: 8.00   3rd Qu.:0  
 Max.   :53.00   Max.   :442.0   Max.   :272.0   Max.   :75.00   Max.   :0  
   prof_nieve          longitud        latitud          altitud      
 Min.   :0.00e+00   Min.   :35.28   Min.   :-8.624   Min.   :   1.0  
 1st Qu.:0.00e+00   1st Qu.:39.49   1st Qu.:-4.680   1st Qu.:  47.0  
 Median :0.00e+00   Median :41.17   Median :-1.411   Median : 251.0  
 Mean   :4.69e-03   Mean   :40.71   Mean   :-1.819   Mean   : 378.3  
 3rd Qu.:0.00e+00   3rd Qu.:42.11   3rd Qu.: 1.165   3rd Qu.: 656.0  
 Max.   :1.48e+02   Max.   :43.57   Max.   : 4.216   Max.   :2143.0  
if (!empty_nodes) summary(df.cluster06)
   fecha_cnt          tmax            tmin            precip           nevada 
 Min.   : 1.00   Min.   :-15.0   Min.   :-84.00   Min.   : 18.00   Min.   :0  
 1st Qu.:16.00   1st Qu.:137.0   1st Qu.: 61.00   1st Qu.: 56.00   1st Qu.:0  
 Median :35.00   Median :172.0   Median : 92.00   Median : 74.00   Median :0  
 Mean   :30.28   Mean   :179.2   Mean   : 94.44   Mean   : 83.46   Mean   :0  
 3rd Qu.:44.00   3rd Qu.:219.0   3rd Qu.:127.00   3rd Qu.:101.00   3rd Qu.:0  
 Max.   :53.00   Max.   :407.0   Max.   :247.00   Max.   :239.00   Max.   :0  
   prof_nieve          longitud        latitud           altitud      
 Min.   :  0.0000   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:  0.0000   1st Qu.:40.95   1st Qu.: -4.846   1st Qu.:  58.0  
 Median :  0.0000   Median :41.88   Median : -1.636   Median : 252.0  
 Mean   :  0.5395   Mean   :41.47   Mean   : -1.779   Mean   : 359.2  
 3rd Qu.:  0.0000   3rd Qu.:42.70   3rd Qu.:  1.633   3rd Qu.: 567.0  
 Max.   :948.0000   Max.   :43.57   Max.   :  4.216   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster07)
   fecha_cnt          tmax            tmin            precip          nevada 
 Min.   : 1.00   Min.   :-58.0   Min.   :-103.0   Min.   :208.0   Min.   :0  
 1st Qu.: 9.75   1st Qu.: 90.0   1st Qu.:  35.5   1st Qu.:245.0   1st Qu.:0  
 Median :40.00   Median :133.0   Median :  75.0   Median :275.5   Median :0  
 Mean   :29.56   Mean   :130.1   Mean   :  69.0   Mean   :296.5   Mean   :0  
 3rd Qu.:46.00   3rd Qu.:179.2   3rd Qu.: 116.2   3rd Qu.:324.2   3rd Qu.:0  
 Max.   :53.00   Max.   :294.0   Max.   : 217.0   Max.   :690.0   Max.   :0  
   prof_nieve         longitud        latitud            altitud      
 Min.   :  0.000   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:  0.000   1st Qu.:40.78   1st Qu.: -5.6000   1st Qu.:  68.6  
 Median :  0.000   Median :42.12   Median :  0.0714   Median : 263.0  
 Mean   :  6.739   Mean   :40.83   Mean   : -2.4923   Mean   : 746.8  
 3rd Qu.:  0.000   3rd Qu.:42.53   3rd Qu.:  1.0989   3rd Qu.:1405.0  
 Max.   :685.000   Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster08)
   fecha_cnt          tmax          tmin             precip           nevada 
 Min.   :28.00   Min.   :-31   Min.   :-155.00   Min.   : 0.000   Min.   :0  
 1st Qu.:46.00   1st Qu.:115   1st Qu.:  18.00   1st Qu.: 0.000   1st Qu.:0  
 Median :48.00   Median :147   Median :  48.00   Median : 2.000   Median :0  
 Mean   :48.06   Mean   :146   Mean   :  48.49   Mean   : 8.869   Mean   :0  
 3rd Qu.:51.00   3rd Qu.:176   3rd Qu.:  78.00   3rd Qu.:13.750   3rd Qu.:0  
 Max.   :53.00   Max.   :297   Max.   : 187.00   Max.   :74.000   Max.   :0  
   prof_nieve           longitud        latitud          altitud      
 Min.   :  0.00000   Min.   :35.28   Min.   :-8.624   Min.   :   1.0  
 1st Qu.:  0.00000   1st Qu.:39.47   1st Qu.:-3.919   1st Qu.:  61.0  
 Median :  0.00000   Median :41.17   Median :-1.117   Median : 349.0  
 Mean   :  0.08002   Mean   :40.52   Mean   :-1.401   Mean   : 404.5  
 3rd Qu.:  0.00000   3rd Qu.:41.91   3rd Qu.: 1.384   3rd Qu.: 674.0  
 Max.   :290.00000   Max.   :43.57   Max.   : 4.216   Max.   :1572.0  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1], dim(df.cluster05)[1], dim(df.cluster06)[1], dim(df.cluster07)[1], dim(df.cluster08)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04", "cluster05", "cluster06", "cluster07", "cluster08"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.hist(df.cluster05)

if (!empty_nodes) mpr.hist(df.cluster06)

if (!empty_nodes) mpr.hist(df.cluster07)

if (!empty_nodes) mpr.hist(df.cluster08)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster05)

if (!empty_nodes) mpr.boxplot(df.cluster06)

if (!empty_nodes) mpr.boxplot(df.cluster07)

if (!empty_nodes) mpr.boxplot(df.cluster08)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
  df.cluster05.grouped <- mpr.group_by_geo(df.cluster05)
  df.cluster06.grouped <- mpr.group_by_geo(df.cluster06)
  df.cluster07.grouped <- mpr.group_by_geo(df.cluster07)
  df.cluster08.grouped <- mpr.group_by_geo(df.cluster08)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster05.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster06.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster07.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster08.grouped)

VisualizaciĂ³n de 10 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=10)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=10)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)
  df.cluster05 <- subset(df, cluster==5)
  df.cluster06 <- subset(df, cluster==6)
  df.cluster07 <- subset(df, cluster==7)
  df.cluster08 <- subset(df, cluster==8)
  df.cluster09 <- subset(df, cluster==9)
  df.cluster10 <- subset(df, cluster==10)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster05 <- select(df.cluster05, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster06 <- select(df.cluster06, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster07 <- select(df.cluster07, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster08 <- select(df.cluster08, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster09 <- select(df.cluster09, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster10 <- select(df.cluster10, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt          tmax            tmin            precip           nevada 
 Min.   : 1.00   Min.   : -3.0   Min.   :-51.00   Min.   :  0.00   Min.   :0  
 1st Qu.:13.00   1st Qu.:101.0   1st Qu.: 28.00   1st Qu.:  0.00   1st Qu.:0  
 Median :26.00   Median :140.0   Median : 61.00   Median :  0.00   Median :0  
 Mean   :26.37   Mean   :144.6   Mean   : 68.24   Mean   :  7.54   Mean   :0  
 3rd Qu.:39.00   3rd Qu.:191.0   3rd Qu.:109.00   3rd Qu.:  3.00   3rd Qu.:0  
 Max.   :53.00   Max.   :263.0   Max.   :184.00   Max.   :193.00   Max.   :0  
   prof_nieve    longitud        latitud         altitud    
 Min.   :0    Min.   :28.31   Min.   :-16.5   Min.   :2371  
 1st Qu.:0    1st Qu.:28.31   1st Qu.:-16.5   1st Qu.:2371  
 Median :0    Median :28.31   Median :-16.5   Median :2371  
 Mean   :0    Mean   :28.31   Mean   :-16.5   Mean   :2371  
 3rd Qu.:0    3rd Qu.:28.31   3rd Qu.:-16.5   3rd Qu.:2371  
 Max.   :0    Max.   :28.31   Max.   :-16.5   Max.   :2371  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt       tmax            tmin           precip           nevada 
 Min.   : 1   Min.   : 88.0   Min.   :-33.0   Min.   : 0.000   Min.   :0  
 1st Qu.: 6   1st Qu.:172.0   1st Qu.: 72.0   1st Qu.: 0.000   1st Qu.:0  
 Median :12   Median :198.0   Median :102.0   Median : 1.000   Median :0  
 Mean   :12   Mean   :203.7   Mean   : 99.9   Mean   : 9.535   Mean   :0  
 3rd Qu.:17   3rd Qu.:233.0   3rd Qu.:129.0   3rd Qu.:14.000   3rd Qu.:0  
 Max.   :28   Max.   :327.0   Max.   :202.0   Max.   :74.000   Max.   :0  
   prof_nieve         longitud        latitud           altitud   
 Min.   :0.00000   Min.   :35.28   Min.   :-6.9492   Min.   :  1  
 1st Qu.:0.00000   1st Qu.:36.64   1st Qu.:-6.2567   1st Qu.: 21  
 Median :0.00000   Median :37.16   Median :-5.5975   Median : 47  
 Mean   :0.00415   Mean   :37.15   Mean   :-4.8032   Mean   :118  
 3rd Qu.:0.00000   3rd Qu.:37.84   3rd Qu.:-3.7892   3rd Qu.: 90  
 Max.   :4.00000   Max.   :39.88   Max.   : 0.8031   Max.   :717  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt          tmax            tmin             precip         nevada 
 Min.   : 1.00   Min.   :-22.0   Min.   :-189.00   Min.   : 0.0   Min.   :0  
 1st Qu.: 6.00   1st Qu.:130.0   1st Qu.:  23.00   1st Qu.: 0.0   1st Qu.:0  
 Median :11.00   Median :164.0   Median :  58.00   Median : 5.0   Median :0  
 Mean   :11.34   Mean   :164.9   Mean   :  56.66   Mean   :11.2   Mean   :0  
 3rd Qu.:17.00   3rd Qu.:201.0   3rd Qu.:  90.00   3rd Qu.:18.0   3rd Qu.:0  
 Max.   :31.00   Max.   :318.0   Max.   : 183.00   Max.   :74.0   Max.   :0  
   prof_nieve          longitud        latitud           altitud      
 Min.   :  0.0000   Min.   :37.18   Min.   :-8.6239   Min.   :   1.0  
 1st Qu.:  0.0000   1st Qu.:40.70   1st Qu.:-3.6325   1st Qu.:  71.0  
 Median :  0.0000   Median :41.52   Median : 0.3994   Median : 353.0  
 Mean   :  0.2299   Mean   :41.32   Mean   :-0.9797   Mean   : 424.2  
 3rd Qu.:  0.0000   3rd Qu.:42.22   3rd Qu.: 1.5208   3rd Qu.: 690.0  
 Max.   :484.0000   Max.   :43.57   Max.   : 4.2156   Max.   :1894.0  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt          tmax              tmin              precip     
 Min.   : 1.00   Min.   :-109.00   Min.   :-175.000   Min.   :  0.0  
 1st Qu.:13.00   1st Qu.:  25.00   1st Qu.: -37.000   1st Qu.:  5.0  
 Median :26.00   Median :  68.00   Median :   3.000   Median : 21.0  
 Mean   :26.74   Mean   :  72.87   Mean   :   4.996   Mean   : 31.8  
 3rd Qu.:41.00   3rd Qu.: 124.00   3rd Qu.:  52.000   3rd Qu.: 48.0  
 Max.   :53.00   Max.   : 230.00   Max.   : 148.000   Max.   :200.0  
     nevada    prof_nieve          longitud        latitud       
 Min.   :0   Min.   :   0.000   Min.   :40.78   Min.   :-4.0103  
 1st Qu.:0   1st Qu.:   0.000   1st Qu.:42.29   1st Qu.: 0.7789  
 Median :0   Median :   0.000   Median :42.47   Median : 1.2717  
 Mean   :0   Mean   :   8.588   Mean   :42.32   Mean   : 0.8968  
 3rd Qu.:0   3rd Qu.:   0.000   3rd Qu.:42.64   3rd Qu.: 1.7150  
 Max.   :0   Max.   :1073.000   Max.   :42.77   Max.   : 2.4378  
    altitud    
 Min.   :1055  
 1st Qu.:2143  
 Median :2247  
 Mean   :2218  
 3rd Qu.:2400  
 Max.   :2535  
if (!empty_nodes) summary(df.cluster05)
   fecha_cnt          tmax            tmin           precip            nevada 
 Min.   : 1.00   Min.   :126.0   Min.   : 67.0   Min.   :  0.000   Min.   :0  
 1st Qu.:13.00   1st Qu.:218.0   1st Qu.:157.0   1st Qu.:  0.000   1st Qu.:0  
 Median :26.00   Median :239.0   Median :177.0   Median :  0.000   Median :0  
 Mean   :26.28   Mean   :240.7   Mean   :177.8   Mean   :  5.133   Mean   :0  
 3rd Qu.:39.00   3rd Qu.:265.0   3rd Qu.:205.0   3rd Qu.:  2.000   3rd Qu.:0  
 Max.   :53.00   Max.   :384.0   Max.   :263.0   Max.   :160.000   Max.   :0  
   prof_nieve    longitud        latitud          altitud   
 Min.   :0    Min.   :27.82   Min.   :-17.89   Min.   : 14  
 1st Qu.:0    1st Qu.:28.05   1st Qu.:-17.75   1st Qu.: 25  
 Median :0    Median :28.46   Median :-16.33   Median : 33  
 Mean   :0    Mean   :28.36   Mean   :-15.97   Mean   :110  
 3rd Qu.:0    3rd Qu.:28.63   3rd Qu.:-13.86   3rd Qu.: 64  
 Max.   :0    Max.   :28.95   Max.   :-13.60   Max.   :632  
if (!empty_nodes) summary(df.cluster06)
   fecha_cnt          tmax            tmin           precip          nevada 
 Min.   :13.00   Min.   :129.0   Min.   : -9.0   Min.   : 0.00   Min.   :0  
 1st Qu.:27.00   1st Qu.:245.0   1st Qu.:127.0   1st Qu.: 0.00   1st Qu.:0  
 Median :32.00   Median :281.0   Median :158.0   Median : 0.00   Median :0  
 Mean   :32.66   Mean   :277.9   Mean   :156.3   Mean   : 5.89   Mean   :0  
 3rd Qu.:38.00   3rd Qu.:311.0   3rd Qu.:187.0   3rd Qu.: 8.00   3rd Qu.:0  
 Max.   :53.00   Max.   :442.0   Max.   :272.0   Max.   :75.00   Max.   :0  
   prof_nieve          longitud        latitud          altitud      
 Min.   :0.00e+00   Min.   :35.28   Min.   :-8.624   Min.   :   1.0  
 1st Qu.:0.00e+00   1st Qu.:39.49   1st Qu.:-4.680   1st Qu.:  47.0  
 Median :0.00e+00   Median :41.17   Median :-1.411   Median : 251.0  
 Mean   :4.69e-03   Mean   :40.71   Mean   :-1.819   Mean   : 378.3  
 3rd Qu.:0.00e+00   3rd Qu.:42.11   3rd Qu.: 1.165   3rd Qu.: 656.0  
 Max.   :1.48e+02   Max.   :43.57   Max.   : 4.216   Max.   :2143.0  
if (!empty_nodes) summary(df.cluster07)
   fecha_cnt          tmax            tmin           precip           nevada 
 Min.   : 1.00   Min.   : 10.0   Min.   :-39.0   Min.   : 18.00   Min.   :0  
 1st Qu.:15.00   1st Qu.:137.0   1st Qu.: 60.0   1st Qu.: 53.00   1st Qu.:0  
 Median :33.00   Median :173.0   Median : 91.0   Median : 68.00   Median :0  
 Mean   :29.63   Mean   :181.5   Mean   : 94.6   Mean   : 71.49   Mean   :0  
 3rd Qu.:44.00   3rd Qu.:224.0   3rd Qu.:128.0   3rd Qu.: 87.00   3rd Qu.:0  
 Max.   :53.00   Max.   :407.0   Max.   :247.0   Max.   :153.00   Max.   :0  
   prof_nieve         longitud        latitud          altitud    
 Min.   :  0.000   Min.   :35.28   Min.   :-8.624   Min.   :   1  
 1st Qu.:  0.000   1st Qu.:40.95   1st Qu.:-4.680   1st Qu.:  59  
 Median :  0.000   Median :41.84   Median :-1.636   Median : 261  
 Mean   :  0.111   Mean   :41.50   Mean   :-1.705   Mean   : 355  
 3rd Qu.:  0.000   3rd Qu.:42.70   3rd Qu.: 1.624   3rd Qu.: 582  
 Max.   :104.000   Max.   :43.57   Max.   : 4.216   Max.   :1894  
if (!empty_nodes) summary(df.cluster08)
   fecha_cnt          tmax            tmin            precip          nevada 
 Min.   : 1.00   Min.   :-58.0   Min.   :-103.0   Min.   :208.0   Min.   :0  
 1st Qu.: 9.75   1st Qu.: 90.0   1st Qu.:  35.5   1st Qu.:245.0   1st Qu.:0  
 Median :40.00   Median :133.0   Median :  75.0   Median :275.5   Median :0  
 Mean   :29.56   Mean   :130.1   Mean   :  69.0   Mean   :296.5   Mean   :0  
 3rd Qu.:46.00   3rd Qu.:179.2   3rd Qu.: 116.2   3rd Qu.:324.2   3rd Qu.:0  
 Max.   :53.00   Max.   :294.0   Max.   : 217.0   Max.   :690.0   Max.   :0  
   prof_nieve         longitud        latitud            altitud      
 Min.   :  0.000   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:  0.000   1st Qu.:40.78   1st Qu.: -5.6000   1st Qu.:  68.6  
 Median :  0.000   Median :42.12   Median :  0.0714   Median : 263.0  
 Mean   :  6.739   Mean   :40.83   Mean   : -2.4923   Mean   : 746.8  
 3rd Qu.:  0.000   3rd Qu.:42.53   3rd Qu.:  1.0989   3rd Qu.:1405.0  
 Max.   :685.000   Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster09)
   fecha_cnt          tmax          tmin             precip           nevada 
 Min.   :28.00   Min.   :-31   Min.   :-155.00   Min.   : 0.000   Min.   :0  
 1st Qu.:46.00   1st Qu.:115   1st Qu.:  18.00   1st Qu.: 0.000   1st Qu.:0  
 Median :48.00   Median :147   Median :  48.00   Median : 2.000   Median :0  
 Mean   :48.06   Mean   :146   Mean   :  48.49   Mean   : 8.869   Mean   :0  
 3rd Qu.:51.00   3rd Qu.:176   3rd Qu.:  78.00   3rd Qu.:13.750   3rd Qu.:0  
 Max.   :53.00   Max.   :297   Max.   : 187.00   Max.   :74.000   Max.   :0  
   prof_nieve           longitud        latitud          altitud      
 Min.   :  0.00000   Min.   :35.28   Min.   :-8.624   Min.   :   1.0  
 1st Qu.:  0.00000   1st Qu.:39.47   1st Qu.:-3.919   1st Qu.:  61.0  
 Median :  0.00000   Median :41.17   Median :-1.117   Median : 349.0  
 Mean   :  0.08002   Mean   :40.52   Mean   :-1.401   Mean   : 404.5  
 3rd Qu.:  0.00000   3rd Qu.:41.91   3rd Qu.: 1.384   3rd Qu.: 674.0  
 Max.   :290.00000   Max.   :43.57   Max.   : 4.216   Max.   :1572.0  
if (!empty_nodes) summary(df.cluster10)
   fecha_cnt          tmax            tmin            precip          nevada 
 Min.   : 1.00   Min.   :-15.0   Min.   :-84.00   Min.   :111.0   Min.   :0  
 1st Qu.:19.00   1st Qu.:133.0   1st Qu.: 68.00   1st Qu.:135.0   1st Qu.:0  
 Median :42.00   Median :166.5   Median : 95.00   Median :153.0   Median :0  
 Mean   :34.32   Mean   :164.9   Mean   : 93.41   Mean   :157.4   Mean   :0  
 3rd Qu.:46.00   3rd Qu.:197.0   3rd Qu.:123.00   3rd Qu.:176.0   3rd Qu.:0  
 Max.   :53.00   Max.   :331.0   Max.   :226.00   Max.   :239.0   Max.   :0  
   prof_nieve         longitud        latitud           altitud      
 Min.   :  0.000   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:  0.000   1st Qu.:40.84   1st Qu.: -5.879   1st Qu.:  44.0  
 Median :  0.000   Median :42.00   Median : -1.787   Median : 176.0  
 Mean   :  3.185   Mean   :41.30   Mean   : -2.237   Mean   : 385.5  
 3rd Qu.:  0.000   3rd Qu.:42.72   3rd Qu.:  1.813   3rd Qu.: 445.0  
 Max.   :948.000   Max.   :43.57   Max.   :  4.216   Max.   :2535.0  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1], dim(df.cluster05)[1], dim(df.cluster06)[1], dim(df.cluster07)[1], dim(df.cluster08)[1], dim(df.cluster09)[1], dim(df.cluster10)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04", "cluster05", "cluster06", "cluster07", "cluster08", "cluster09", "cluster10"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.hist(df.cluster05)

if (!empty_nodes) mpr.hist(df.cluster06)

if (!empty_nodes) mpr.hist(df.cluster07)

if (!empty_nodes) mpr.hist(df.cluster08)

if (!empty_nodes) mpr.hist(df.cluster09)

if (!empty_nodes) mpr.hist(df.cluster10)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster05)

if (!empty_nodes) mpr.boxplot(df.cluster06)

if (!empty_nodes) mpr.boxplot(df.cluster07)

if (!empty_nodes) mpr.boxplot(df.cluster08)

if (!empty_nodes) mpr.boxplot(df.cluster09)

if (!empty_nodes) mpr.boxplot(df.cluster10)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
  df.cluster05.grouped <- mpr.group_by_geo(df.cluster05)
  df.cluster06.grouped <- mpr.group_by_geo(df.cluster06)
  df.cluster07.grouped <- mpr.group_by_geo(df.cluster07)
  df.cluster08.grouped <- mpr.group_by_geo(df.cluster08)
  df.cluster09.grouped <- mpr.group_by_geo(df.cluster09)
  df.cluster10.grouped <- mpr.group_by_geo(df.cluster10)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster05.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster06.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster07.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster08.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster09.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster10.grouped)

LS0tCnRpdGxlOiAiQW7DoWxpc2lzIGRlIG1vZGVsb3MgU09NIC0gRnJlY3VlbmNpYSBkYXRvcyBkZSBlbnRyYWRhOiBzZW1hbmEiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCiMgTW9kZWxvCgoqIElEOiAxMzgKKiBEZXNjcmlwY2nDs246IAoqIEZyZWN1ZW5jaWE6IHNlbWFuYQoqIFZhcmlhYmxlczogZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkCiogRGltZW5zaW9uZXMgZGVsIG1hcGE6IDUsNQoqIEl0ZXJhY2lvbmVzOiAxMDAwMAoqIFBhcsOhbWV0cm9zIGFkaWNpb25hbGVzOiAKCmBgYHtyfQpzb3VyY2UoIi4uLy4uL2xpYi9zb20tdXRpbHMuUiIpCnNvdXJjZSgiLi4vLi4vbGliL21hcHMtdXRpbHMuUiIpCmBgYAoKIyBDYXJnYSBkZWwgbW9kZWxvIGRlc2RlIGRpc2NvCgpgYGB7cn0KbXByLnNldF9iYXNlX3BhdGhfYW5hbHlzaXMoKQptb2RlbCA8LSBtcHIubG9hZF9tb2RlbCgic29tLTEzOC5yZHMueHoiKQpzdW1tYXJ5KG1vZGVsKQpgYGAKCmBgYHtyfQpwbG90KG1vZGVsLCB0eXBlPSJjaGFuZ2VzIikKYGBgCgojIENhcmdhIGRlbCBkYXRhc2V0IGRlIGVudHJhZGEKCmBgYHtyfQpkZiA8LSBtcHIubG9hZF9kYXRhKCJkYXRvc19zZW1hbmFfMmsuY3N2Lnh6IikKYGBgCgpgYGB7cn0KZGYKYGBgCgpgYGB7cn0Kc3VtbWFyeShkZikKYGBgCgojIENhcmdhIGRlIGxvcyBtYXBhcwoKYGBge3J9CndvcmxkIDwtIG5lX2NvdW50cmllcyhzY2FsZSA9ICJtZWRpdW0iLCByZXR1cm5jbGFzcyA9ICJzZiIpCnNwYWluIDwtIHN1YnNldCh3b3JsZCwgYWRtaW4gPT0gIlNwYWluIikKYGBgCgojIE1hcGEgZGUgZGVuc2lkYWQKCmBgYHtyfQpwbG90KG1vZGVsLCB0eXBlPSJjb3VudCIsIHNoYXBlID0gInN0cmFpZ2h0IiwgcGFsZXR0ZS5uYW1lID0gbXByLmRlZ3JhZGUuYmxldSkKYGBgCgpOw7ptZXJvIGRlIGVsZW1lbnRvcyBlbiBjYWRhIGNlbGRhOgoKYGBge3J9Cm5iIDwtIHRhYmxlKG1vZGVsJHVuaXQuY2xhc3NpZikKcHJpbnQobmIpCmBgYApDb21wcm9iYWNpw7NuIGRlIG5vZG9zIHZhY8Otb3M6CgpgYGB7cn0KZGltX21vZGVsIDwtIDUqNTsKbGVuX25iID0gbGVuZ3RoKG5iKTsKZW1wdHlfbm9kZXMgPC0gZGltX21vZGVsICE9IGxlbl9uYjsKaWYgKGVtcHR5X25vZGVzKSB7CiAgcHJpbnQocGFzdGUoIltXYXJuaW5nXSBFeGlzdGVuIG5vZG9zIHZhY8Otb3M6ICIsIGxlbl9uYiwgIi8iLCBkaW1fbW9kZWwpKQp9CmBgYAoKIyBNYXBhIGRlIGRpc3RhbmNpYSBlbnRyZSB2ZWNpbm9zCgpgYGB7cn0KcGxvdChtb2RlbCwgdHlwZT0iZGlzdC5uZWlnaGJvdXJzIiwgc2hhcGUgPSAic3RyYWlnaHQiKQpgYGAKCiMgSW5mbHVlbmNpYSBkZSBsYXMgdmFyaWFibGVzCgpgYGB7cn0KbW9kZWxfY29sbmFtZXMgPSBjKCJmZWNoYV9jbnQiLCAidG1heCIsICJ0bWluIiwgInByZWNpcCIsICJsb25naXR1ZCIsICJsYXRpdHVkIiwgImFsdGl0dWQiKQptb2RlbF9uY29sID0gbGVuZ3RoKG1vZGVsX2NvbG5hbWVzKQpgYGAKCiMjIE1hcGEgZGUgdmFyaWFibGVzLgoKYGBge3J9CnBsb3QobW9kZWwsIHNoYXBlID0gInN0cmFpZ2h0IikKYGBgCgojIyBNYXBhIGRlIGNhbG9yIHBvciB2YXJpYWJsZQoKYGBge3J9CnBhcihtZnJvdz1jKDMsNCkpCmZvciAoaiBpbiAxOm1vZGVsX25jb2wpIHsKICBwbG90KG1vZGVsLCB0eXBlPSJwcm9wZXJ0eSIsIHByb3BlcnR5PWdldENvZGVzKG1vZGVsLDEpWyxqXSwKICAgIHBhbGV0dGUubmFtZT1tcHIuY29vbEJsdWVIb3RSZWQsCiAgICBtYWluPW1vZGVsX2NvbG5hbWVzW2pdLAogICAgY2V4PTAuNSwgc2hhcGUgPSAic3RyYWlnaHQiKQp9CmBgYAoKIyMgQ29ycmVsYWNpw7NuIHBhcmEgY2FkYSBjb2x1bW5hIGRlbCB2ZWN0b3IgZGUgbm9kb3MKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgY29yIDwtIGFwcGx5KGdldENvZGVzKG1vZGVsLDEpLCAyLCBtcHIud2VpZ2h0ZWQuY29ycmVsYXRpb24sIHc9bmIsIHNvbT1tb2RlbCkKICBwcmludChjb3IpCn0KYGBgCgpSZXByZXNlbnRhY2nDs24gZGUgY2FkYSB2YXJpYWJsZSBlbiB1biBtYXBhIGRlIGZhY3RvcmVzOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBwYXIobWZyb3c9YygxLDEpKQogIHBsb3QoY29yWzEsXSwgY29yWzIsXSwgeGxpbT1jKC0xLDEpLCB5bGltPWMoLTEsMSksIHR5cGU9Im4iKQogIGxpbmVzKGMoLTEsMSksYygwLDApKQogIGxpbmVzKGMoMCwwKSxjKC0xLDEpKQogIHRleHQoY29yWzEsXSwgY29yWzIsXSwgbGFiZWxzPW1vZGVsX2NvbG5hbWVzLCBjZXg9MC43NSkKICBzeW1ib2xzKDAsMCxjaXJjbGVzPTEsaW5jaGVzPUYsYWRkPVQpCn0KYGBgCgpJbXBvcnRhbmNpYSBkZSBjYWRhIHZhcmlhYmxlIC0gdmFyaWFuemEgcG9uZGVyYWRhIHBvciBlbCB0YW1hw7FvIGRlIGxhIGNlbGRhOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBzaWdtYTIgPC0gc3FydChhcHBseShnZXRDb2Rlcyhtb2RlbCwxKSwyLGZ1bmN0aW9uKHgsZWZmZWN0aWYpCiAgICAge208LXN1bShlZmZlY3RpZiooeC13ZWlnaHRlZC5tZWFuKHgsZWZmZWN0aWYpKV4yKS8oc3VtKGVmZmVjdGlmKS0xKX0sCiAgICAgZWZmZWN0aWY9bmIpKQogIHByaW50KHNvcnQoc2lnbWEyLGRlY3JlYXNpbmc9VCkpCn0KYGBgCgojIENsdXN0ZXJpbmcKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgaGFjIDwtIG1wci5oYWMobW9kZWwsIG5iKQp9CmBgYAoKIyMgVmlzdWFsaXphY2nDs24gZGUgMyBjbMO6c3RlcmVzOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBwbG90KGhhYywgaGFuZz0tMSwgbGFiZWxzPUYpCiAgcmVjdC5oY2x1c3QoaGFjLCBrPTMpCn0KYGBgCgojIyMgVmlzdWFsaXphY2nDs24gZGUgbG9zIGNsw7pzdGVycyBlbiBlbCBtYXBhCgpBIHF1w6kgY2zDunN0ZXIgcGVydGVuZWNlIGNhZGEgbm9kbyBkZWwgbWFwYSBkZSBrb2hvbmVuOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBncm91cHMgPC0gY3V0cmVlKGhhYywgaz0zKQogIHBsb3QobW9kZWwsIHR5cGU9Im1hcHBpbmciLAogICAgYmdjb2w9Yygic3RlZWxibHVlMSIsInNpZW5uYTEiLCJ5ZWxsb3dncmVlbiIsInJlZCIsImJsdWUiLCJ5ZWxsb3ciLCJwdXJwbGUiLCJncmVlbiIsIndoaXRlIiwiIzFmNzdiNCIsICcjZmY3ZjBlJywgJyMyY2EwMmMnLCAnI2Q2MjcyOCcsICcjOTQ2N2JkJywgJyM4YzU2NGInLCAnI2UzNzdjMicpW2dyb3Vwc10sCiAgICBzaGFwZSA9ICJzdHJhaWdodCIsIGxhYmVscyA9ICIiKQogIGFkZC5jbHVzdGVyLmJvdW5kYXJpZXMobW9kZWwsIGNsdXN0ZXJpbmc9Z3JvdXBzKQp9CmBgYAoKIyMjIEFuw6FsaXNpcyBkZSBsYXMgb2JzZXJ2YWNpb25lcyBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBBc2lnbmFtb3MgYSBjYWRhIHJlZ2lzdHJvIHN1IGNsw7pzdGVyCiAgZGYkY2x1c3RlciA8LSBncm91cHNbbW9kZWwkdW5pdC5jbGFzc2lmXQp9CmBgYAoKTnVldm9zIGRhdGFmcmFtZXMgcG9yIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBDcmVvIG51ZXZvcyBkYXRhZnJhbWVzLCB1bm8gcG9yIGNhZGEgY2zDunN0ZXIuCiAgZGYuY2x1c3RlcjAxIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MSkKICBkZi5jbHVzdGVyMDIgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0yKQogIGRmLmNsdXN0ZXIwMyA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTMpCgogICMgRXh0cmFpZ28gZGVsIGRhdGFmcmFtZSBsYXMgZmVhdHVyZXMuCiAgZGYuY2x1c3RlcjAxIDwtIHNlbGVjdChkZi5jbHVzdGVyMDEsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwMiA8LSBzZWxlY3QoZGYuY2x1c3RlcjAyLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDMgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMywgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCn0KYGBgCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMykKYGBgCgojIyMjIE7Dum1lcm8gZGUgZWxlbWVudG9zIGVuIGNhZGEgY2zDunN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgZGYuY2x1c3RlcnMuZGltIDwtIGMoZGltKGRmLmNsdXN0ZXIwMSlbMV0sIGRpbShkZi5jbHVzdGVyMDIpWzFdLCBkaW0oZGYuY2x1c3RlcjAzKVsxXSkKICBiYXJwbG90KGRmLmNsdXN0ZXJzLmRpbSwKICAgICAgICAgIG5hbWVzLmFyZyA9IGMoImNsdXN0ZXIwMSIsICJjbHVzdGVyMDIiLCAiY2x1c3RlcjAzIiksCiAgICAgICAgICBjb2wgPSAic3RlZWxibHVlMSIpCn0KYGBgCgojIyMjIERpc3RyaWJ1Y2nDs24gZGUgbG9zIGRhdG9zCgpgYGB7ciBmaWcuaGVpZ2h0PTd9CmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDMpCmBgYAoKYGBge3IgZmlnLmhlaWdodD01fQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAzKQpgYGAKCiMjIyBMb2NhbGl6YWNpw7NuIGdlb2dyw6FmaWNhIGRlIGxhcyBlc3RhY2lvbmVzIGRlIG1lZGlkYSBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQojIEFncnVwYSBwb3IgbG9uZ2l0dWQgeSBsYXRpdHVkIHBhcmEgcmVsbGVuYXIgZWwgbWFwYSBjb24gbWVub3MgZGF0b3MuCmlmICghZW1wdHlfbm9kZXMpIHsKICBkZi5jbHVzdGVyMDEuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMSkKICBkZi5jbHVzdGVyMDIuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMikKICBkZi5jbHVzdGVyMDMuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMykKfQpgYGAKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMS5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMi5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMy5ncm91cGVkKQpgYGAKCiMjIFZpc3VhbGl6YWNpw7NuIGRlIDQgY2zDunN0ZXJlczoKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgcGxvdChoYWMsIGhhbmc9LTEsIGxhYmVscz1GKQogIHJlY3QuaGNsdXN0KGhhYywgaz00KQp9CmBgYAoKIyMjIFZpc3VhbGl6YWNpw7NuIGRlIGxvcyBjbMO6c3RlcnMgZW4gZWwgbWFwYQoKQSBxdcOpIGNsw7pzdGVyIHBlcnRlbmVjZSBjYWRhIG5vZG8gZGVsIG1hcGEgZGUga29ob25lbjoKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgZ3JvdXBzIDwtIGN1dHJlZShoYWMsIGs9NCkKICBwbG90KG1vZGVsLCB0eXBlPSJtYXBwaW5nIiwKICAgIGJnY29sPWMoInN0ZWVsYmx1ZTEiLCJzaWVubmExIiwieWVsbG93Z3JlZW4iLCJyZWQiLCJibHVlIiwieWVsbG93IiwicHVycGxlIiwiZ3JlZW4iLCJ3aGl0ZSIsIiMxZjc3YjQiLCAnI2ZmN2YwZScsICcjMmNhMDJjJywgJyNkNjI3MjgnLCAnIzk0NjdiZCcsICcjOGM1NjRiJywgJyNlMzc3YzInKVtncm91cHNdLAogICAgc2hhcGUgPSAic3RyYWlnaHQiLCBsYWJlbHMgPSAiIikKICBhZGQuY2x1c3Rlci5ib3VuZGFyaWVzKG1vZGVsLCBjbHVzdGVyaW5nPWdyb3VwcykKfQpgYGAKCiMjIyBBbsOhbGlzaXMgZGUgbGFzIG9ic2VydmFjaW9uZXMgZGUgY2FkYSBjbHVzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogICMgQXNpZ25hbW9zIGEgY2FkYSByZWdpc3RybyBzdSBjbMO6c3RlcgogIGRmJGNsdXN0ZXIgPC0gZ3JvdXBzW21vZGVsJHVuaXQuY2xhc3NpZl0KfQpgYGAKCk51ZXZvcyBkYXRhZnJhbWVzIHBvciBjbHVzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogICMgQ3JlbyBudWV2b3MgZGF0YWZyYW1lcywgdW5vIHBvciBjYWRhIGNsw7pzdGVyLgogIGRmLmNsdXN0ZXIwMSA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTEpCiAgZGYuY2x1c3RlcjAyIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MikKICBkZi5jbHVzdGVyMDMgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0zKQogIGRmLmNsdXN0ZXIwNCA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTQpCgogICMgRXh0cmFpZ28gZGVsIGRhdGFmcmFtZSBsYXMgZmVhdHVyZXMuCiAgZGYuY2x1c3RlcjAxIDwtIHNlbGVjdChkZi5jbHVzdGVyMDEsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwMiA8LSBzZWxlY3QoZGYuY2x1c3RlcjAyLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDMgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMywgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA0IDwtIHNlbGVjdChkZi5jbHVzdGVyMDQsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQp9CmBgYAoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA0KQpgYGAKCiMjIyMgTsO6bWVybyBkZSBlbGVtZW50b3MgZW4gY2FkYSBjbMO6c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBkZi5jbHVzdGVycy5kaW0gPC0gYyhkaW0oZGYuY2x1c3RlcjAxKVsxXSwgZGltKGRmLmNsdXN0ZXIwMilbMV0sIGRpbShkZi5jbHVzdGVyMDMpWzFdLCBkaW0oZGYuY2x1c3RlcjA0KVsxXSkKICBiYXJwbG90KGRmLmNsdXN0ZXJzLmRpbSwKICAgICAgICAgIG5hbWVzLmFyZyA9IGMoImNsdXN0ZXIwMSIsICJjbHVzdGVyMDIiLCAiY2x1c3RlcjAzIiwgImNsdXN0ZXIwNCIpLAogICAgICAgICAgY29sID0gInN0ZWVsYmx1ZTEiKQp9CmBgYAoKIyMjIyBEaXN0cmlidWNpw7NuIGRlIGxvcyBkYXRvcwoKYGBge3IgZmlnLmhlaWdodD03fQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDQpCmBgYAoKYGBge3IgZmlnLmhlaWdodD01fQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDQpCmBgYAoKIyMjIExvY2FsaXphY2nDs24gZ2VvZ3LDoWZpY2EgZGUgbGFzIGVzdGFjaW9uZXMgZGUgbWVkaWRhIGRlIGNhZGEgY2x1c3RlcgoKYGBge3J9CiMgQWdydXBhIHBvciBsb25naXR1ZCB5IGxhdGl0dWQgcGFyYSByZWxsZW5hciBlbCBtYXBhIGNvbiBtZW5vcyBkYXRvcy4KaWYgKCFlbXB0eV9ub2RlcykgewogIGRmLmNsdXN0ZXIwMS5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAxKQogIGRmLmNsdXN0ZXIwMi5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAyKQogIGRmLmNsdXN0ZXIwMy5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAzKQogIGRmLmNsdXN0ZXIwNC5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA0KQp9CmBgYAoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAxLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAyLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAzLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA0Lmdyb3VwZWQpCmBgYAoKIyMgVmlzdWFsaXphY2nDs24gZGUgNSBjbMO6c3RlcmVzOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBwbG90KGhhYywgaGFuZz0tMSwgbGFiZWxzPUYpCiAgcmVjdC5oY2x1c3QoaGFjLCBrPTUpCn0KYGBgCgojIyMgVmlzdWFsaXphY2nDs24gZGUgbG9zIGNsw7pzdGVycyBlbiBlbCBtYXBhCgpBIHF1w6kgY2zDunN0ZXIgcGVydGVuZWNlIGNhZGEgbm9kbyBkZWwgbWFwYSBkZSBrb2hvbmVuOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBncm91cHMgPC0gY3V0cmVlKGhhYywgaz01KQogIHBsb3QobW9kZWwsIHR5cGU9Im1hcHBpbmciLAogICAgYmdjb2w9Yygic3RlZWxibHVlMSIsInNpZW5uYTEiLCJ5ZWxsb3dncmVlbiIsInJlZCIsImJsdWUiLCJ5ZWxsb3ciLCJwdXJwbGUiLCJncmVlbiIsIndoaXRlIiwiIzFmNzdiNCIsICcjZmY3ZjBlJywgJyMyY2EwMmMnLCAnI2Q2MjcyOCcsICcjOTQ2N2JkJywgJyM4YzU2NGInLCAnI2UzNzdjMicpW2dyb3Vwc10sCiAgICBzaGFwZSA9ICJzdHJhaWdodCIsIGxhYmVscyA9ICIiKQogIGFkZC5jbHVzdGVyLmJvdW5kYXJpZXMobW9kZWwsIGNsdXN0ZXJpbmc9Z3JvdXBzKQp9CmBgYAoKIyMjIEFuw6FsaXNpcyBkZSBsYXMgb2JzZXJ2YWNpb25lcyBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBBc2lnbmFtb3MgYSBjYWRhIHJlZ2lzdHJvIHN1IGNsw7pzdGVyCiAgZGYkY2x1c3RlciA8LSBncm91cHNbbW9kZWwkdW5pdC5jbGFzc2lmXQp9CmBgYAoKTnVldm9zIGRhdGFmcmFtZXMgcG9yIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBDcmVvIG51ZXZvcyBkYXRhZnJhbWVzLCB1bm8gcG9yIGNhZGEgY2zDunN0ZXIuCiAgZGYuY2x1c3RlcjAxIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MSkKICBkZi5jbHVzdGVyMDIgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0yKQogIGRmLmNsdXN0ZXIwMyA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTMpCiAgZGYuY2x1c3RlcjA0IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NCkKICBkZi5jbHVzdGVyMDUgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT01KQoKICAjIEV4dHJhaWdvIGRlbCBkYXRhZnJhbWUgbGFzIGZlYXR1cmVzLgogIGRmLmNsdXN0ZXIwMSA8LSBzZWxlY3QoZGYuY2x1c3RlcjAxLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDIgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMiwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjAzIDwtIHNlbGVjdChkZi5jbHVzdGVyMDMsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNCA8LSBzZWxlY3QoZGYuY2x1c3RlcjA0LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDUgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNSwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCn0KYGBgCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDQpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA1KQpgYGAKCiMjIyMgTsO6bWVybyBkZSBlbGVtZW50b3MgZW4gY2FkYSBjbMO6c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBkZi5jbHVzdGVycy5kaW0gPC0gYyhkaW0oZGYuY2x1c3RlcjAxKVsxXSwgZGltKGRmLmNsdXN0ZXIwMilbMV0sIGRpbShkZi5jbHVzdGVyMDMpWzFdLCBkaW0oZGYuY2x1c3RlcjA0KVsxXSwgZGltKGRmLmNsdXN0ZXIwNSlbMV0pCiAgYmFycGxvdChkZi5jbHVzdGVycy5kaW0sCiAgICAgICAgICBuYW1lcy5hcmcgPSBjKCJjbHVzdGVyMDEiLCAiY2x1c3RlcjAyIiwgImNsdXN0ZXIwMyIsICJjbHVzdGVyMDQiLCAiY2x1c3RlcjA1IiksCiAgICAgICAgICBjb2wgPSAic3RlZWxibHVlMSIpCn0KYGBgCgojIyMjIERpc3RyaWJ1Y2nDs24gZGUgbG9zIGRhdG9zCgpgYGB7ciBmaWcuaGVpZ2h0PTd9CmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwNCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA1KQpgYGAKCmBgYHtyIGZpZy5oZWlnaHQ9NX0KaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA0KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDUpCmBgYAoKIyMjIExvY2FsaXphY2nDs24gZ2VvZ3LDoWZpY2EgZGUgbGFzIGVzdGFjaW9uZXMgZGUgbWVkaWRhIGRlIGNhZGEgY2x1c3RlcgoKYGBge3J9CiMgQWdydXBhIHBvciBsb25naXR1ZCB5IGxhdGl0dWQgcGFyYSByZWxsZW5hciBlbCBtYXBhIGNvbiBtZW5vcyBkYXRvcy4KaWYgKCFlbXB0eV9ub2RlcykgewogIGRmLmNsdXN0ZXIwMS5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAxKQogIGRmLmNsdXN0ZXIwMi5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAyKQogIGRmLmNsdXN0ZXIwMy5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAzKQogIGRmLmNsdXN0ZXIwNC5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA0KQogIGRmLmNsdXN0ZXIwNS5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA1KQp9CmBgYAoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAxLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAyLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAzLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA0Lmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA1Lmdyb3VwZWQpCmBgYAoKIyMgVmlzdWFsaXphY2nDs24gZGUgNiBjbMO6c3RlcmVzOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBwbG90KGhhYywgaGFuZz0tMSwgbGFiZWxzPUYpCiAgcmVjdC5oY2x1c3QoaGFjLCBrPTYpCn0KYGBgCgojIyMgVmlzdWFsaXphY2nDs24gZGUgbG9zIGNsw7pzdGVycyBlbiBlbCBtYXBhCgpBIHF1w6kgY2zDunN0ZXIgcGVydGVuZWNlIGNhZGEgbm9kbyBkZWwgbWFwYSBkZSBrb2hvbmVuOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBncm91cHMgPC0gY3V0cmVlKGhhYywgaz02KQogIHBsb3QobW9kZWwsIHR5cGU9Im1hcHBpbmciLAogICAgYmdjb2w9Yygic3RlZWxibHVlMSIsInNpZW5uYTEiLCJ5ZWxsb3dncmVlbiIsInJlZCIsImJsdWUiLCJ5ZWxsb3ciLCJwdXJwbGUiLCJncmVlbiIsIndoaXRlIiwiIzFmNzdiNCIsICcjZmY3ZjBlJywgJyMyY2EwMmMnLCAnI2Q2MjcyOCcsICcjOTQ2N2JkJywgJyM4YzU2NGInLCAnI2UzNzdjMicpW2dyb3Vwc10sCiAgICBzaGFwZSA9ICJzdHJhaWdodCIsIGxhYmVscyA9ICIiKQogIGFkZC5jbHVzdGVyLmJvdW5kYXJpZXMobW9kZWwsIGNsdXN0ZXJpbmc9Z3JvdXBzKQp9CmBgYAoKIyMjIEFuw6FsaXNpcyBkZSBsYXMgb2JzZXJ2YWNpb25lcyBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBBc2lnbmFtb3MgYSBjYWRhIHJlZ2lzdHJvIHN1IGNsw7pzdGVyCiAgZGYkY2x1c3RlciA8LSBncm91cHNbbW9kZWwkdW5pdC5jbGFzc2lmXQp9CmBgYAoKTnVldm9zIGRhdGFmcmFtZXMgcG9yIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBDcmVvIG51ZXZvcyBkYXRhZnJhbWVzLCB1bm8gcG9yIGNhZGEgY2zDunN0ZXIuCiAgZGYuY2x1c3RlcjAxIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MSkKICBkZi5jbHVzdGVyMDIgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0yKQogIGRmLmNsdXN0ZXIwMyA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTMpCiAgZGYuY2x1c3RlcjA0IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NCkKICBkZi5jbHVzdGVyMDUgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT01KQogIGRmLmNsdXN0ZXIwNiA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTYpCgogICMgRXh0cmFpZ28gZGVsIGRhdGFmcmFtZSBsYXMgZmVhdHVyZXMuCiAgZGYuY2x1c3RlcjAxIDwtIHNlbGVjdChkZi5jbHVzdGVyMDEsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwMiA8LSBzZWxlY3QoZGYuY2x1c3RlcjAyLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDMgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMywgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA0IDwtIHNlbGVjdChkZi5jbHVzdGVyMDQsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNSA8LSBzZWxlY3QoZGYuY2x1c3RlcjA1LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDYgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNiwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCn0KYGBgCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDQpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA1KQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwNikKYGBgCgojIyMjIE7Dum1lcm8gZGUgZWxlbWVudG9zIGVuIGNhZGEgY2zDunN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgZGYuY2x1c3RlcnMuZGltIDwtIGMoZGltKGRmLmNsdXN0ZXIwMSlbMV0sIGRpbShkZi5jbHVzdGVyMDIpWzFdLCBkaW0oZGYuY2x1c3RlcjAzKVsxXSwgZGltKGRmLmNsdXN0ZXIwNClbMV0sIGRpbShkZi5jbHVzdGVyMDUpWzFdLCBkaW0oZGYuY2x1c3RlcjA2KVsxXSkKICBiYXJwbG90KGRmLmNsdXN0ZXJzLmRpbSwKICAgICAgICAgIG5hbWVzLmFyZyA9IGMoImNsdXN0ZXIwMSIsICJjbHVzdGVyMDIiLCAiY2x1c3RlcjAzIiwgImNsdXN0ZXIwNCIsICJjbHVzdGVyMDUiLCAiY2x1c3RlcjA2IiksCiAgICAgICAgICBjb2wgPSAic3RlZWxibHVlMSIpCn0KYGBgCgojIyMjIERpc3RyaWJ1Y2nDs24gZGUgbG9zIGRhdG9zCgpgYGB7ciBmaWcuaGVpZ2h0PTd9CmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwNCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA1KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDYpCmBgYAoKYGBge3IgZmlnLmhlaWdodD01fQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwNSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA2KQpgYGAKCiMjIyBMb2NhbGl6YWNpw7NuIGdlb2dyw6FmaWNhIGRlIGxhcyBlc3RhY2lvbmVzIGRlIG1lZGlkYSBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQojIEFncnVwYSBwb3IgbG9uZ2l0dWQgeSBsYXRpdHVkIHBhcmEgcmVsbGVuYXIgZWwgbWFwYSBjb24gbWVub3MgZGF0b3MuCmlmICghZW1wdHlfbm9kZXMpIHsKICBkZi5jbHVzdGVyMDEuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMSkKICBkZi5jbHVzdGVyMDIuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMikKICBkZi5jbHVzdGVyMDMuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMykKICBkZi5jbHVzdGVyMDQuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNCkKICBkZi5jbHVzdGVyMDUuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNSkKICBkZi5jbHVzdGVyMDYuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNikKfQpgYGAKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMS5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMi5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMy5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNC5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNS5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNi5ncm91cGVkKQpgYGAKCiMjIFZpc3VhbGl6YWNpw7NuIGRlIDggY2zDunN0ZXJlczoKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgcGxvdChoYWMsIGhhbmc9LTEsIGxhYmVscz1GKQogIHJlY3QuaGNsdXN0KGhhYywgaz04KQp9CmBgYAoKIyMjIFZpc3VhbGl6YWNpw7NuIGRlIGxvcyBjbMO6c3RlcnMgZW4gZWwgbWFwYQoKQSBxdcOpIGNsw7pzdGVyIHBlcnRlbmVjZSBjYWRhIG5vZG8gZGVsIG1hcGEgZGUga29ob25lbjoKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgZ3JvdXBzIDwtIGN1dHJlZShoYWMsIGs9OCkKICBwbG90KG1vZGVsLCB0eXBlPSJtYXBwaW5nIiwKICAgIGJnY29sPWMoInN0ZWVsYmx1ZTEiLCJzaWVubmExIiwieWVsbG93Z3JlZW4iLCJyZWQiLCJibHVlIiwieWVsbG93IiwicHVycGxlIiwiZ3JlZW4iLCJ3aGl0ZSIsIiMxZjc3YjQiLCAnI2ZmN2YwZScsICcjMmNhMDJjJywgJyNkNjI3MjgnLCAnIzk0NjdiZCcsICcjOGM1NjRiJywgJyNlMzc3YzInKVtncm91cHNdLAogICAgc2hhcGUgPSAic3RyYWlnaHQiLCBsYWJlbHMgPSAiIikKICBhZGQuY2x1c3Rlci5ib3VuZGFyaWVzKG1vZGVsLCBjbHVzdGVyaW5nPWdyb3VwcykKfQpgYGAKCiMjIyBBbsOhbGlzaXMgZGUgbGFzIG9ic2VydmFjaW9uZXMgZGUgY2FkYSBjbHVzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogICMgQXNpZ25hbW9zIGEgY2FkYSByZWdpc3RybyBzdSBjbMO6c3RlcgogIGRmJGNsdXN0ZXIgPC0gZ3JvdXBzW21vZGVsJHVuaXQuY2xhc3NpZl0KfQpgYGAKCk51ZXZvcyBkYXRhZnJhbWVzIHBvciBjbHVzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogICMgQ3JlbyBudWV2b3MgZGF0YWZyYW1lcywgdW5vIHBvciBjYWRhIGNsw7pzdGVyLgogIGRmLmNsdXN0ZXIwMSA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTEpCiAgZGYuY2x1c3RlcjAyIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MikKICBkZi5jbHVzdGVyMDMgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0zKQogIGRmLmNsdXN0ZXIwNCA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTQpCiAgZGYuY2x1c3RlcjA1IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NSkKICBkZi5jbHVzdGVyMDYgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT02KQogIGRmLmNsdXN0ZXIwNyA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTcpCiAgZGYuY2x1c3RlcjA4IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09OCkKCiAgIyBFeHRyYWlnbyBkZWwgZGF0YWZyYW1lIGxhcyBmZWF0dXJlcy4KICBkZi5jbHVzdGVyMDEgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMSwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjAyIDwtIHNlbGVjdChkZi5jbHVzdGVyMDIsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwMyA8LSBzZWxlY3QoZGYuY2x1c3RlcjAzLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDQgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNCwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA1IDwtIHNlbGVjdChkZi5jbHVzdGVyMDUsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNiA8LSBzZWxlY3QoZGYuY2x1c3RlcjA2LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDcgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNywgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA4IDwtIHNlbGVjdChkZi5jbHVzdGVyMDgsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQp9CmBgYAoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA0KQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwNSkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDYpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA3KQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwOCkKYGBgCgojIyMjIE7Dum1lcm8gZGUgZWxlbWVudG9zIGVuIGNhZGEgY2zDunN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgZGYuY2x1c3RlcnMuZGltIDwtIGMoZGltKGRmLmNsdXN0ZXIwMSlbMV0sIGRpbShkZi5jbHVzdGVyMDIpWzFdLCBkaW0oZGYuY2x1c3RlcjAzKVsxXSwgZGltKGRmLmNsdXN0ZXIwNClbMV0sIGRpbShkZi5jbHVzdGVyMDUpWzFdLCBkaW0oZGYuY2x1c3RlcjA2KVsxXSwgZGltKGRmLmNsdXN0ZXIwNylbMV0sIGRpbShkZi5jbHVzdGVyMDgpWzFdKQogIGJhcnBsb3QoZGYuY2x1c3RlcnMuZGltLAogICAgICAgICAgbmFtZXMuYXJnID0gYygiY2x1c3RlcjAxIiwgImNsdXN0ZXIwMiIsICJjbHVzdGVyMDMiLCAiY2x1c3RlcjA0IiwgImNsdXN0ZXIwNSIsICJjbHVzdGVyMDYiLCAiY2x1c3RlcjA3IiwgImNsdXN0ZXIwOCIpLAogICAgICAgICAgY29sID0gInN0ZWVsYmx1ZTEiKQp9CmBgYAoKIyMjIyBEaXN0cmlidWNpw7NuIGRlIGxvcyBkYXRvcwoKYGBge3IgZmlnLmhlaWdodD03fQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwNSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA2KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDcpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwOCkKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTV9CmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwNCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA1KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDYpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwNykKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA4KQpgYGAKCiMjIyBMb2NhbGl6YWNpw7NuIGdlb2dyw6FmaWNhIGRlIGxhcyBlc3RhY2lvbmVzIGRlIG1lZGlkYSBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQojIEFncnVwYSBwb3IgbG9uZ2l0dWQgeSBsYXRpdHVkIHBhcmEgcmVsbGVuYXIgZWwgbWFwYSBjb24gbWVub3MgZGF0b3MuCmlmICghZW1wdHlfbm9kZXMpIHsKICBkZi5jbHVzdGVyMDEuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMSkKICBkZi5jbHVzdGVyMDIuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMikKICBkZi5jbHVzdGVyMDMuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMykKICBkZi5jbHVzdGVyMDQuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNCkKICBkZi5jbHVzdGVyMDUuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNSkKICBkZi5jbHVzdGVyMDYuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNikKICBkZi5jbHVzdGVyMDcuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNykKICBkZi5jbHVzdGVyMDguZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwOCkKfQpgYGAKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMS5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMi5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMy5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNC5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNS5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNi5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNy5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwOC5ncm91cGVkKQpgYGAKCiMjIFZpc3VhbGl6YWNpw7NuIGRlIDEwIGNsw7pzdGVyZXM6CgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIHBsb3QoaGFjLCBoYW5nPS0xLCBsYWJlbHM9RikKICByZWN0LmhjbHVzdChoYWMsIGs9MTApCn0KYGBgCgojIyMgVmlzdWFsaXphY2nDs24gZGUgbG9zIGNsw7pzdGVycyBlbiBlbCBtYXBhCgpBIHF1w6kgY2zDunN0ZXIgcGVydGVuZWNlIGNhZGEgbm9kbyBkZWwgbWFwYSBkZSBrb2hvbmVuOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBncm91cHMgPC0gY3V0cmVlKGhhYywgaz0xMCkKICBwbG90KG1vZGVsLCB0eXBlPSJtYXBwaW5nIiwKICAgIGJnY29sPWMoInN0ZWVsYmx1ZTEiLCJzaWVubmExIiwieWVsbG93Z3JlZW4iLCJyZWQiLCJibHVlIiwieWVsbG93IiwicHVycGxlIiwiZ3JlZW4iLCJ3aGl0ZSIsIiMxZjc3YjQiLCAnI2ZmN2YwZScsICcjMmNhMDJjJywgJyNkNjI3MjgnLCAnIzk0NjdiZCcsICcjOGM1NjRiJywgJyNlMzc3YzInKVtncm91cHNdLAogICAgc2hhcGUgPSAic3RyYWlnaHQiLCBsYWJlbHMgPSAiIikKICBhZGQuY2x1c3Rlci5ib3VuZGFyaWVzKG1vZGVsLCBjbHVzdGVyaW5nPWdyb3VwcykKfQpgYGAKCiMjIyBBbsOhbGlzaXMgZGUgbGFzIG9ic2VydmFjaW9uZXMgZGUgY2FkYSBjbHVzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogICMgQXNpZ25hbW9zIGEgY2FkYSByZWdpc3RybyBzdSBjbMO6c3RlcgogIGRmJGNsdXN0ZXIgPC0gZ3JvdXBzW21vZGVsJHVuaXQuY2xhc3NpZl0KfQpgYGAKCk51ZXZvcyBkYXRhZnJhbWVzIHBvciBjbHVzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogICMgQ3JlbyBudWV2b3MgZGF0YWZyYW1lcywgdW5vIHBvciBjYWRhIGNsw7pzdGVyLgogIGRmLmNsdXN0ZXIwMSA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTEpCiAgZGYuY2x1c3RlcjAyIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MikKICBkZi5jbHVzdGVyMDMgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0zKQogIGRmLmNsdXN0ZXIwNCA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTQpCiAgZGYuY2x1c3RlcjA1IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NSkKICBkZi5jbHVzdGVyMDYgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT02KQogIGRmLmNsdXN0ZXIwNyA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTcpCiAgZGYuY2x1c3RlcjA4IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09OCkKICBkZi5jbHVzdGVyMDkgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT05KQogIGRmLmNsdXN0ZXIxMCA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTEwKQoKICAjIEV4dHJhaWdvIGRlbCBkYXRhZnJhbWUgbGFzIGZlYXR1cmVzLgogIGRmLmNsdXN0ZXIwMSA8LSBzZWxlY3QoZGYuY2x1c3RlcjAxLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDIgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMiwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjAzIDwtIHNlbGVjdChkZi5jbHVzdGVyMDMsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNCA8LSBzZWxlY3QoZGYuY2x1c3RlcjA0LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDUgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNSwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA2IDwtIHNlbGVjdChkZi5jbHVzdGVyMDYsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNyA8LSBzZWxlY3QoZGYuY2x1c3RlcjA3LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDggPC0gc2VsZWN0KGRmLmNsdXN0ZXIwOCwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA5IDwtIHNlbGVjdChkZi5jbHVzdGVyMDksIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIxMCA8LSBzZWxlY3QoZGYuY2x1c3RlcjEwLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKfQpgYGAKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwNCkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDUpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA2KQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwNykKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDgpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA5KQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIxMCkKYGBgCgojIyMjIE7Dum1lcm8gZGUgZWxlbWVudG9zIGVuIGNhZGEgY2zDunN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgZGYuY2x1c3RlcnMuZGltIDwtIGMoZGltKGRmLmNsdXN0ZXIwMSlbMV0sIGRpbShkZi5jbHVzdGVyMDIpWzFdLCBkaW0oZGYuY2x1c3RlcjAzKVsxXSwgZGltKGRmLmNsdXN0ZXIwNClbMV0sIGRpbShkZi5jbHVzdGVyMDUpWzFdLCBkaW0oZGYuY2x1c3RlcjA2KVsxXSwgZGltKGRmLmNsdXN0ZXIwNylbMV0sIGRpbShkZi5jbHVzdGVyMDgpWzFdLCBkaW0oZGYuY2x1c3RlcjA5KVsxXSwgZGltKGRmLmNsdXN0ZXIxMClbMV0pCiAgYmFycGxvdChkZi5jbHVzdGVycy5kaW0sCiAgICAgICAgICBuYW1lcy5hcmcgPSBjKCJjbHVzdGVyMDEiLCAiY2x1c3RlcjAyIiwgImNsdXN0ZXIwMyIsICJjbHVzdGVyMDQiLCAiY2x1c3RlcjA1IiwgImNsdXN0ZXIwNiIsICJjbHVzdGVyMDciLCAiY2x1c3RlcjA4IiwgImNsdXN0ZXIwOSIsICJjbHVzdGVyMTAiKSwKICAgICAgICAgIGNvbCA9ICJzdGVlbGJsdWUxIikKfQpgYGAKCiMjIyMgRGlzdHJpYnVjacOzbiBkZSBsb3MgZGF0b3MKCmBgYHtyIGZpZy5oZWlnaHQ9N30KaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA0KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDUpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwNikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA3KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDgpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwOSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjEwKQpgYGAKCmBgYHtyIGZpZy5oZWlnaHQ9NX0KaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA0KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDUpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwNikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA3KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDgpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwOSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjEwKQpgYGAKCiMjIyBMb2NhbGl6YWNpw7NuIGdlb2dyw6FmaWNhIGRlIGxhcyBlc3RhY2lvbmVzIGRlIG1lZGlkYSBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQojIEFncnVwYSBwb3IgbG9uZ2l0dWQgeSBsYXRpdHVkIHBhcmEgcmVsbGVuYXIgZWwgbWFwYSBjb24gbWVub3MgZGF0b3MuCmlmICghZW1wdHlfbm9kZXMpIHsKICBkZi5jbHVzdGVyMDEuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMSkKICBkZi5jbHVzdGVyMDIuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMikKICBkZi5jbHVzdGVyMDMuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMykKICBkZi5jbHVzdGVyMDQuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNCkKICBkZi5jbHVzdGVyMDUuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNSkKICBkZi5jbHVzdGVyMDYuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNikKICBkZi5jbHVzdGVyMDcuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNykKICBkZi5jbHVzdGVyMDguZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwOCkKICBkZi5jbHVzdGVyMDkuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwOSkKICBkZi5jbHVzdGVyMTAuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIxMCkKfQpgYGAKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMS5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMi5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMy5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNC5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNS5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNi5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNy5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwOC5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwOS5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIxMC5ncm91cGVkKQpgYGAK